Index: applications/editors/josm/plugins/namefinder/README
===================================================================
--- applications/editors/josm/plugins/namefinder/README	(revision 2925)
+++ applications/editors/josm/plugins/namefinder/README	(revision 2925)
@@ -0,0 +1,6 @@
+A very simple first implementation of a Name Finder that will
+add a "place" tab to the download dialog. This is a "proof of concept"
+intended for others to build on ;-)
+
+Frederik Ramm <frederik@remote.org>
+
Index: applications/editors/josm/plugins/namefinder/build.xml
===================================================================
--- applications/editors/josm/plugins/namefinder/build.xml	(revision 2925)
+++ applications/editors/josm/plugins/namefinder/build.xml	(revision 2925)
@@ -0,0 +1,35 @@
+<project name="namefinder" default="dist" basedir=".">
+
+    <fileset id="required_libs" dir="../../josm/lib">
+            <include name="MinML2.jar"/>
+    </fileset>
+
+	<target name="dist" depends="compile">
+
+        <!-- jars -->
+        <unjar dest="build">
+                <fileset refid="required_libs" />
+        </unjar>
+
+		<!-- create josm-custom.jar -->
+		<jar destfile="namefinder.jar" basedir="build">
+			<manifest>
+                <attribute name="Plugin-Class" value="namefinder.NameFinderPlugin" />
+                <attribute name="Plugin-Description" value="Allows selection of download areas by name, using an external service" />
+			</manifest>
+		</jar>
+	</target>
+
+	<target name="compile" depends="init">
+		<javac srcdir="namefinder" classpath="../../josm/build/:../../josm/lib/MinML2.jar" destdir="build" />
+	</target>
+
+	<target name="init">
+		<mkdir dir="build" />
+	</target>
+
+	<target name="clean">
+		<delete dir="build" />
+	</target>
+
+</project>
Index: applications/editors/josm/plugins/namefinder/namefinder/NameFinderPlugin.java
===================================================================
--- applications/editors/josm/plugins/namefinder/namefinder/NameFinderPlugin.java	(revision 2925)
+++ applications/editors/josm/plugins/namefinder/namefinder/NameFinderPlugin.java	(revision 2925)
@@ -0,0 +1,28 @@
+package namefinder;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.List;
+
+import org.openstreetmap.josm.gui.download.DownloadSelection;
+import org.openstreetmap.josm.plugins.Plugin;
+
+/**
+ * Main class for the name finder plugin.
+ * 
+ * 
+ * @author Frederik Ramm <frederik@remote.org>
+ *
+ */
+public class NameFinderPlugin extends Plugin 
+{    
+    public NameFinderPlugin() 
+    {
+    }
+    
+    @Override public void addDownloadSelection(List<DownloadSelection> list) 
+    {
+    	list.add(new PlaceSelection());
+    }
+	
+}
Index: applications/editors/josm/plugins/namefinder/namefinder/PlaceSelection.java
===================================================================
--- applications/editors/josm/plugins/namefinder/namefinder/PlaceSelection.java	(revision 2925)
+++ applications/editors/josm/plugins/namefinder/namefinder/PlaceSelection.java	(revision 2925)
@@ -0,0 +1,233 @@
+package namefinder;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+import org.openstreetmap.josm.gui.download.DownloadDialog;
+import org.openstreetmap.josm.gui.download.DownloadSelection;
+import org.openstreetmap.josm.tools.GBC;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import uk.co.wilson.xml.MinML2;
+
+public class PlaceSelection implements DownloadSelection {
+
+	private JTextField searchTerm = new JTextField();
+	private JButton submitSearch = new JButton(tr("Search..."));
+	private DefaultListModel searchResults = new DefaultListModel();
+	private JList searchResultDisplay = new JList(searchResults);
+	private boolean updatingSelf;
+	
+	/**
+	 * Data storage for search results.
+	 */
+	class SearchResult 
+	{
+		public String name;
+		public String description;
+		public double lat;
+		public double lon;
+		public int zoom;
+	}
+	
+	/**
+	 * A very primitive parser for the name finder's output. 
+	 * Structure of xml described here:  http://wiki.openstreetmap.org/index.php/Name_finder
+	 *
+	 */
+	private class Parser extends MinML2
+	{
+		private SearchResult currentResult = null;
+		private StringBuffer description = null;
+		private int depth = 0;
+		/**
+		 * Detect starting elements.
+		 * 
+		 */
+		@Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException 
+		{
+			depth++;
+			try 
+			{
+				if (qName.equals("searchresults")) 
+				{
+					searchResults.clear();
+				}
+				else if (qName.equals("named") && (depth == 2))
+				{	
+					currentResult = new PlaceSelection.SearchResult();
+					currentResult.name = atts.getValue("name");
+					currentResult.lat = Double.parseDouble(atts.getValue("lat"));
+					currentResult.lon = Double.parseDouble(atts.getValue("lon"));
+					currentResult.zoom = Integer.parseInt(atts.getValue("zoom"));
+					searchResults.addElement(currentResult);
+				}
+				else if (qName.equals("description") && (depth == 3))
+				{
+					description = new StringBuffer();
+				} 
+			}
+			catch (NumberFormatException x) 
+			{
+				x.printStackTrace(); // SAXException does not chain correctly
+				throw new SAXException(x.getMessage(), x);
+			} 
+			catch (NullPointerException x) 
+			{
+				x.printStackTrace(); // SAXException does not chain correctly
+				throw new SAXException(tr("NullPointerException. Possible some missing tags."), x);
+			}
+		}
+		/** 
+		 * Detect ending elements.
+		 */
+		@Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException
+		{
+
+			if (qName.equals("searchresults")) 
+			{
+			}
+			else if (qName.equals("description") && description != null)
+			{
+				currentResult.description = description.toString();
+				description = null;
+			}
+			depth--;
+
+		}
+		/** 
+		 * Read characters for description.
+		 */
+		@Override public void characters(char[] data, int start, int length) throws org.xml.sax.SAXException
+		{
+			if (description != null) 
+			{
+				description.append(data, start, length);
+			}
+		}
+	}
+	
+	/**
+	 * This queries David Earl's server. Needless to say, stuff should be configurable, and 
+	 * error handling improved.
+	 */
+	public void queryServer()
+	{
+		try
+		{
+			URL url = new URL("http://www.frankieandshadow.com/osm/search.xml?find="+java.net.URLEncoder.encode(searchTerm.getText(), "UTF-8"));
+			HttpURLConnection activeConnection = (HttpURLConnection)url.openConnection();
+			System.out.println("got return: "+activeConnection.getResponseCode());
+			activeConnection.setConnectTimeout(15000);
+			InputStream inputStream = activeConnection.getInputStream();
+			new Parser().parse(new InputStreamReader(inputStream, "UTF-8"));
+		}
+		catch (Exception x) 
+		{
+			JOptionPane.showMessageDialog(Main.parent,tr("Cannot read place search results from server"));
+			x.printStackTrace();
+		}
+	}
+	
+	// add a new tab to the download dialog
+	public void addGui(final DownloadDialog gui) {
+		JPanel panel = new JPanel();
+		panel.setLayout(new GridBagLayout());
+		panel.add(new JLabel(tr("Enter a place name to search for:")), GBC.eol());
+		panel.add(searchTerm, GBC.std().fill(GBC.HORIZONTAL));
+		panel.add(submitSearch, GBC.eol());
+
+		
+		GBC c = GBC.eol();
+		c.gridwidth = 2;
+		panel.add(new JScrollPane(searchResultDisplay), c);
+		gui.tabpane.add(panel, "Places");
+		
+		// when the button is clicked
+		submitSearch.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				queryServer();
+			}
+		});
+		
+		// display search results in list just by name, and add tooltip 
+		// for description. would also be possible to use a table model
+		// instead of list, and display lat/lon etc.
+		searchResultDisplay.setCellRenderer(new DefaultListCellRenderer() {
+			@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+				super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+				if (value != null) {
+					setText(((SearchResult)value).name);
+					setToolTipText("<html>"+((SearchResult)value).description+"</html>");
+				}
+				return this;
+			}
+		});
+		
+		// if item is selected in list, notify dialog
+		//searchResultDisplay.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		searchResultDisplay.addListSelectionListener(new ListSelectionListener() {
+			public void valueChanged(ListSelectionEvent lse) {
+				if (lse.getValueIsAdjusting()) return;
+				SearchResult r = null;
+				try 
+				{
+					r = (SearchResult) searchResults.getElementAt(lse.getFirstIndex());
+				}
+				catch (Exception x)
+				{
+					// Ignore
+				}
+				if (r != null)
+				{
+					double size = 180.0 / Math.pow(2, r.zoom);
+					gui.minlat = r.lat - size / 2;
+					gui.maxlat = r.lat + size / 2;
+					gui.minlon = r.lon - size;
+					gui.maxlon = r.lon + size;
+					updatingSelf = true;
+					gui.boundingBoxChanged(null);
+					updatingSelf = false;
+				}
+			}
+		});
+	}
+
+	// if bounding box selected on other tab, de-select item
+	public void boundingBoxChanged(DownloadDialog gui) {
+		if (!updatingSelf) searchResultDisplay.clearSelection();
+	}
+}
