Index: src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- src/org/openstreetmap/josm/tools/ImageProvider.java	(Revision 4398)
+++ src/org/openstreetmap/josm/tools/ImageProvider.java	(Arbeitskopie)
@@ -3,10 +3,6 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import com.kitfox.svg.SVGDiagram;
-import com.kitfox.svg.SVGException;
-import com.kitfox.svg.SVGUniverse;
-
 import java.awt.Component;
 import java.awt.Cursor;
 import java.awt.Dimension;
@@ -20,6 +16,7 @@
 import java.awt.Toolkit;
 import java.awt.Transparency;
 import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,11 +33,23 @@
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
 
+import org.apache.commons.codec.digest.DigestUtils;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.plugins.PluginHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
 
+import com.kitfox.svg.SVGDiagram;
+import com.kitfox.svg.SVGException;
+import com.kitfox.svg.SVGUniverse;
+
 /**
  * Helper class to support the application with images.
  * @author imi
@@ -79,8 +88,8 @@
         if (icon == null) {
             String ext = name.indexOf('.') != -1 ? "" : ".???";
             throw new NullPointerException(tr(
-            "Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.",
-            name+ext));
+                    "Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.",
+                    name+ext));
         }
         return icon;
     }
@@ -116,7 +125,7 @@
     public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name, File archive, boolean sanitize) {
         return getIfAvailable(dirs, id, subdir, name, archive, null, sanitize);
     }
-    
+
     /**
      * The full path of the image is either a url (starting with http://)
      * or something like
@@ -128,19 +137,113 @@
      *                  it will try both extensions.
      * @param archive   A zip file where the image is located (may be null).
      * @param dim       The dimensions of the image if it should be scaled. null if the
-     *                  original size of the image should be returned. The width 
+     *                  original size of the image should be returned. The width
      *                  part of the dimension can be -1. Then it will scale the width
      *                  in the same way as the height. (And the other way around.)
      * @param sanitize  If the image should be repainted to a new BufferedImage to work
      *                  around certain issues.
      */
     public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name, File archive, Dimension dim, boolean sanitize) {
-        ImageResource ir = getIfAvailableImpl(dirs, id, subdir, name, archive);
-        if (ir == null)
-            return null;
-        return ir.getImageIcon(dim == null ? ImageResource.DEFAULT_DIMENSION : dim, sanitize);
+        ImageIcon icon = new ImageIcon();
+        if (name != null && name.startsWith("wiki://")) {
+            getIfAvailableWikiImpl(icon, dirs, id, name, dim, sanitize);
+        } else {
+            ImageResource ir = getIfAvailableImpl(dirs, id, subdir, name, archive);
+            if (ir == null)
+                return null;
+            else {
+                icon = ir.getImageIcon(dim == null ? ImageResource.DEFAULT_DIMENSION : dim, sanitize);
+            }
+        }
+        return icon;
     }
 
+    private static void getIfAvailableWikiImpl(final ImageIcon icon, Collection<String> dirs, String id, final String name, Dimension dim, final boolean sanitize) {
+        ImageResource ir = cache.get(name);
+        if (ir != null) {
+            icon.setImage(ir.getImageIcon(dim == null ? ImageResource.DEFAULT_DIMENSION : dim, sanitize).getImage());
+        } else {
+            // do not return null, since we will loose control over the icon object else
+            icon.setImage(getIfAvailable(dirs, id, null, "misc/no_icon.png", null, sanitize).getImage());
+
+            Main.worker.execute(new Runnable(){
+                private boolean fetchImpl(String url) {
+                    try {
+                        MirroredInputStream is = new MirroredInputStream(url, new File(Main.pref.getPreferencesDir(),
+                        "images").toString());
+
+                        Image img = Toolkit.getDefaultToolkit().createImage(is.getFile().toURI().toURL());
+                        if (sanitize) {
+                            img = sanitize(img);
+                        }
+                        cache.put(name, new ImageResource(img, sanitize));
+
+                        // finally, update the icon image that up to now displayed "no_icon"
+                        icon.setImage(img);
+                        return true;
+                    } catch (IOException e) {
+                        System.out.println("INFO: fetching " + url + "failed");
+                        return false;
+                    }
+                }
+
+                private String getImgUrlFromInfoPage(final String base, final String fn) {
+                    try {
+                        final XMLReader parser = XMLReaderFactory.createXMLReader();
+                        parser.setContentHandler(new DefaultHandler() {
+                            @Override
+                            public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+                                System.out.println();
+                                if (localName.equalsIgnoreCase("img")) {
+                                    String val = atts.getValue("src");
+                                    if (val.endsWith(fn))
+                                        throw new SAXException(val);  // parsing done, quit early
+                                }
+                            }
+                        });
+
+                        parser.setEntityResolver(new EntityResolver() {
+                            public InputSource resolveEntity (String publicId, String systemId) {
+                                return new InputSource(new ByteArrayInputStream(new byte[0]));
+                            }
+                        });
+
+                        parser.parse(new InputSource(new MirroredInputStream(
+                                base + fn,
+                                new File(Main.pref.getPreferencesDir(), "images").toString()
+                        )));
+                    } catch (Exception e) {
+                        if (!(e instanceof SAXException)) {
+                            System.out.println("INFO: parsing " + base + fn + "failed");
+                        } else
+                            return e.getMessage();
+                    }
+
+                    return "";
+                }
+
+                public void run() {
+                    final String[] baseurls = {
+                            Main.pref.get("url.osm-wiki-images", "http://wiki.openstreetmap.org/w/images/"),
+                            Main.pref.get("url.commons-wiki-images", "http://upload.wikimedia.org/wikipedia/commons/"),
+                            Main.pref.get("url.osm-wiki-infopage", "http://wiki.openstreetmap.org/wiki/File:"),
+                    };
+                    final String fn = name.substring(name.lastIndexOf('/') + 1);
+                    final String fn_md5 = DigestUtils.md5Hex(fn);
+
+                    for (String b : baseurls) {
+                        if ( fetchImpl(b.endsWith(":")
+                                ? (getImgUrlFromInfoPage(b, fn))
+                                        : (b + fn_md5.substring(0,1)+"/" + fn_md5.substring(0,2)+"/" + fn))
+                        ) {
+                            break;
+                        }
+                    }
+                }
+            });
+        }
+    }
+
     private static ImageResource getIfAvailableImpl(Collection<String> dirs, String id, String subdir, String name, File archive) {
         if (name == null)
             return null;
@@ -192,30 +295,31 @@
                 if (ir != null) return ir;
 
                 switch (place) {
-                    case ARCHIVE:
-                        if (archive != null) {
-                            ir = getIfAvailableZip(full_name, archive, type);
-                            if (ir != null) {
-                                cache.put(cache_name, ir);
-                                return ir;
-                            }
-                        }
-                        break;
-                    case LOCAL:
-                        // getImageUrl() does a ton of "stat()" calls and gets expensive
-                        // and redundant when you have a whole ton of objects. So,
-                        // index the cache by the name of the icon we're looking for
-                        // and don't bother to create a URL unless we're actually
-                        // creating the image.
-                        URL path = getImageUrl(full_name, dirs);
-                        if (path == null)
-                            continue;
-                        ir = getIfAvailableLocalURL(path, type);
+                case ARCHIVE:
+                    if (archive != null) {
+                        ir = getIfAvailableZip(full_name, archive, type);
                         if (ir != null) {
                             cache.put(cache_name, ir);
                             return ir;
                         }
-                        break;
+                    }
+                    break;
+                case LOCAL:
+                    // getImageUrl() does a ton of "stat()" calls and gets expensive
+                    // and redundant when you have a whole ton of objects. So,
+                    // index the cache by the name of the icon we're looking for
+                    // and don't bother to create a URL unless we're actually
+                    // creating the image.
+                    URL path = getImageUrl(full_name, dirs);
+                    if (path == null) {
+                        continue;
+                    }
+                    ir = getIfAvailableLocalURL(path, type);
+                    if (ir != null) {
+                        cache.put(cache_name, ir);
+                        return ir;
+                    }
+                    break;
                 }
             }
         }
@@ -227,15 +331,15 @@
             MirroredInputStream is = new MirroredInputStream(url,
                     new File(Main.pref.getPreferencesDir(), "images").toString());
             switch (type) {
-                case SVG:
-                    URI uri = getSvgUniverse().loadSVG(is, is.getFile().toURI().toURL().toString());
-                    SVGDiagram svg = getSvgUniverse().getDiagram(uri);
-                    return svg == null ? null : new ImageResource(svg);
-                case OTHER:
-                    Image img = Toolkit.getDefaultToolkit().createImage(is.getFile().toURI().toURL());
-                    return img == null ? null : new ImageResource(img, false);
-                default:
-                    throw new AssertionError();
+            case SVG:
+                URI uri = getSvgUniverse().loadSVG(is, is.getFile().toURI().toURL().toString());
+                SVGDiagram svg = getSvgUniverse().getDiagram(uri);
+                return svg == null ? null : new ImageResource(svg);
+            case OTHER:
+                Image img = Toolkit.getDefaultToolkit().createImage(is.getFile().toURI().toURL());
+                return img == null ? null : new ImageResource(img, false);
+            default:
+                throw new AssertionError();
             }
         } catch (IOException e) {
             return null;
@@ -257,21 +361,21 @@
                 try {
                     is = zipFile.getInputStream(entry);
                     switch (type) {
-                        case SVG:
-                            URI uri = getSvgUniverse().loadSVG(is, full_name);
-                            SVGDiagram svg = getSvgUniverse().getDiagram(uri);
-                            return svg == null ? null : new ImageResource(svg);
-                        case OTHER:
-                            while(size > 0)
-                            {
-                                int l = is.read(buf, offs, size);
-                                offs += l;
-                                size -= l;
-                            }
-                            Image img = Toolkit.getDefaultToolkit().createImage(buf);
-                            return img == null ? null : new ImageResource(img, false);
-                        default:
-                            throw new AssertionError();
+                    case SVG:
+                        URI uri = getSvgUniverse().loadSVG(is, full_name);
+                        SVGDiagram svg = getSvgUniverse().getDiagram(uri);
+                        return svg == null ? null : new ImageResource(svg);
+                    case OTHER:
+                        while(size > 0)
+                        {
+                            int l = is.read(buf, offs, size);
+                            offs += l;
+                            size -= l;
+                        }
+                        Image img = Toolkit.getDefaultToolkit().createImage(buf);
+                        return img == null ? null : new ImageResource(img, false);
+                    default:
+                        throw new AssertionError();
                     }
                 } finally {
                     if (is != null) {
@@ -294,15 +398,15 @@
 
     private static ImageResource getIfAvailableLocalURL(URL path, ImageType type) {
         switch (type) {
-            case SVG:
-                URI uri = getSvgUniverse().loadSVG(path);
-                SVGDiagram svg = getSvgUniverse().getDiagram(uri);
-                return svg == null ? null : new ImageResource(svg);
-            case OTHER:
-                Image img = Toolkit.getDefaultToolkit().createImage(path);
-                return img == null ? null : new ImageResource(img, false);
-            default:
-                throw new AssertionError();
+        case SVG:
+            URI uri = getSvgUniverse().loadSVG(path);
+            SVGDiagram svg = getSvgUniverse().getDiagram(uri);
+            return svg == null ? null : new ImageResource(svg);
+        case OTHER:
+            Image img = Toolkit.getDefaultToolkit().createImage(path);
+            return img == null ? null : new ImageResource(img, false);
+        default:
+            throw new AssertionError();
         }
     }
 
