Index: src/org/openstreetmap/josm/actions/AboutAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AboutAction.java	(revision 68)
+++ src/org/openstreetmap/josm/actions/AboutAction.java	(revision 69)
@@ -13,5 +13,4 @@
 import java.util.regex.Pattern;
 
-import javax.swing.JEditorPane;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
@@ -20,10 +19,9 @@
 import javax.swing.JTabbedPane;
 import javax.swing.JTextArea;
-import javax.swing.event.HyperlinkEvent;
-import javax.swing.event.HyperlinkListener;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.GBC;
 import org.openstreetmap.josm.gui.ImageProvider;
+import org.openstreetmap.josm.tools.UrlLabel;
 
 /**
@@ -59,18 +57,5 @@
 		info.add(new JLabel("last change at "+time), GBC.eop());
 		info.add(new JLabel("Homepage"), GBC.std().insets(0,0,10,0));
-		JEditorPane homepage = new JEditorPane();
-		homepage.setContentType("text/html");
-		homepage.setText("<html><a href=\"http://wiki.eigenheimstrasse.de/wiki/JOSM\">" +
-				"http://wiki.eigenheimstrasse.de/wiki/JOSM</a></html>");
-		homepage.setEditable(false);
-		homepage.setOpaque(false);
-		homepage.addHyperlinkListener(new HyperlinkListener(){
-			public void hyperlinkUpdate(HyperlinkEvent e) {
-				if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
-					//TODO: Open browser
-				}
-			}
-		});
-		info.add(homepage, GBC.eol());
+		info.add(new UrlLabel("http://wiki.eigenheimstrasse.de/wiki/JOSM"), GBC.eol());
 		
 		
Index: src/org/openstreetmap/josm/data/osm/visitor/SearchVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/SearchVisitor.java	(revision 68)
+++ 	(revision )
@@ -1,108 +1,0 @@
-package org.openstreetmap.josm.data.osm.visitor;
-
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.openstreetmap.josm.data.osm.LineSegment;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Way;
-
-/**
- * Searches in the primitives for specific search strings.
- * @author Imi
- */
-public class SearchVisitor implements Visitor {
-
-	/**
-	 * One search criteria. Criterias are seperated by space.
-	 */
-	static class Criteria {
-		/**
-		 * If <code>true</code>, the criteria must match. <code>false</code> for the
-		 * criteria to NOT match.
-		 */
-		boolean match = true;
-		/**
-		 * Any Key must match this.
-		 */
-		String key;
-		/**
-		 * The value to the key must match the value. 
-		 */
-		String value;
-		/**
-		 * Any key or value must match this.
-		 */
-		String any;
-
-		enum Type {node, segment, way}
-		/**
-		 * Must be of the given type. (<code>null</code> for any type)
-		 */
-		Type type;
-	}
-	
-	private Collection<Criteria> criterias = new LinkedList<Criteria>();
-	private String search;
-
-	public SearchVisitor(String searchStr) {
-		search = searchStr;
-		for (String token = nextToken(); !token.equals(""); token = nextToken()) {
-			Criteria crit = new Criteria();
-			if (token.charAt(0) == '-' && token.length() > 1) {
-				crit.match = false;
-				token = token.substring(1);
-			}
-			if (token.charAt(0) == '"')
-				crit.any = token.substring(1);
-			else {
-				int colon = token.indexOf(':');
-				if (colon != -1) {
-					crit.key = token.substring(0, colon);
-					crit.value = token.substring(colon+1);
-				} else
-					crit.any = token;
-			}
-		}
-	}
-	
-	public void visit(Node n) {
-		// TODO Auto-generated method stub
-
-	}
-
-	public void visit(LineSegment ls) {
-		// TODO Auto-generated method stub
-
-	}
-
-	public void visit(Way w) {
-		// TODO Auto-generated method stub
-
-	}
-
-	
-	/**
-	 * Return the next token in the search string. Update the string as well.
-	 */
-	private String nextToken() {
-		if ("".equals(search))
-			return "";
-		if (search.charAt(0) == '"' || search.startsWith("-\"")) {
-			int start = search.charAt(0) == '"' ? 1 : 2;
-			int i = search.indexOf('"', start);
-			if (i == -1) {
-				String token = search;
-				search = "";
-				return token;
-			}
-			String token = start == 1 ? search.substring(0, i) : "-"+search.substring(1, i);
-			search = search.substring(i+1);
-			return token;
-		}
-		int i = search.indexOf(' ');
-		String token = search.substring(0, i);
-		search = search.substring(i+1);
-		return token;
-	}
-}
Index: src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 68)
+++ src/org/openstreetmap/josm/gui/dialogs/SelectionListDialog.java	(revision 69)
@@ -10,5 +10,4 @@
 import java.awt.event.MouseEvent;
 import java.util.Collection;
-import java.util.Map.Entry;
 
 import javax.swing.DefaultListModel;
@@ -27,4 +26,5 @@
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
+import org.openstreetmap.josm.tools.SearchCompiler;
 
 /**
@@ -84,32 +84,18 @@
 				JLabel l = new JLabel("Please enter a search string.");
 				l.setToolTipText("<html>Fulltext search.<ul>" +
-						"<li>Baker Street  - search for everything with 'Baker Street' in any key or name.</li>" +
-						"<li>name:Bak  - search for every object with key=name and 'Bak' anywhere in the value.</li>" +
-						"<li>foot:  - search for everything with the key=foot set to any value." +
+						"<li><code>Baker Street</code>  - 'Baker' and 'Street' in any key or name.</li>" +
+						"<li><code>\"Baker Street\"</code>  - 'Baker Street' in any key or name.</li>" +
+						"<li><code>name:Bak</code>  - 'Bak' anywhere in the name.</li>" +
+						"<li><code>-name:Bak</code>  - not 'Bak' in the name.</li>" +
+						"<li><code>foot:</code>  - key=foot set to any value." +
 						"</ul></html>");
 				lastSearch = (String)JOptionPane.showInputDialog(Main.main,l,"Search",JOptionPane.INFORMATION_MESSAGE,null,null,lastSearch);
 				if (lastSearch == null)
 					return;
-				Main.main.ds.clearSelection();
-				for (OsmPrimitive osm : Main.main.ds.allNonDeletedPrimitives()) {
-					for (Entry<String, String> ent : osm.entrySet()) {
-						if (match(lastSearch, ent.getKey(), ent.getValue())) {
-							osm.setSelected(true);
-							break;
-						}
-					}
-				}
+				SearchCompiler.Match matcher = SearchCompiler.compile(lastSearch);
+				for (OsmPrimitive osm : Main.main.ds.allNonDeletedPrimitives())
+					osm.setSelected(matcher.match(osm));
 				selectionChanged(Main.main.ds.getSelected());
 				Main.main.getMapFrame().repaint();
-			}
-			private boolean match(String search, String key, String value) {
-				int colon = search.indexOf(':');
-				if (colon == -1)
-					return key.indexOf(search) != -1 || value.indexOf(search) != -1;
-				String searchKey = search.substring(0, colon);
-				String searchValue = search.substring(colon+1);
-				if (searchKey.equals("type") && (searchValue.equals("segment")||searchValue.equals("way")||searchValue.equals("node")))
-					return true;
-				return key.equals(searchKey) && value.indexOf(searchValue) != -1;
 			}
 		});
Index: src/org/openstreetmap/josm/tools/OpenBrowser.java
===================================================================
--- src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 69)
+++ src/org/openstreetmap/josm/tools/OpenBrowser.java	(revision 69)
@@ -0,0 +1,27 @@
+package org.openstreetmap.josm.tools;
+
+import java.io.IOException;
+
+/**
+ * Helper to open platform web browser on different platforms
+ * @author Imi
+ */
+public class OpenBrowser {
+
+	/**
+	 * @return <code>null</code> for success or a string in case of an error.
+	 */
+	public static String displayUrl(String url) {
+		String os = System.getProperty("os.name");
+		try {
+			if (os != null && os.startsWith("Windows"))
+				Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
+			else {
+				//...
+			}
+		} catch (IOException e) {
+			return e.getMessage();
+		}
+		return null;
+	}
+}
Index: src/org/openstreetmap/josm/tools/SearchCompiler.java
===================================================================
--- src/org/openstreetmap/josm/tools/SearchCompiler.java	(revision 69)
+++ src/org/openstreetmap/josm/tools/SearchCompiler.java	(revision 69)
@@ -0,0 +1,242 @@
+package org.openstreetmap.josm.tools;
+
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.util.Map.Entry;
+
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+
+/**
+ * Implements a google-like search.
+ * @author Imi
+ */
+public class SearchCompiler {
+
+	abstract public static class Match {
+		abstract public boolean match(OsmPrimitive osm);
+	}
+	
+	private static class Always extends Match {
+		@Override public boolean match(OsmPrimitive osm) {
+			return true;
+		}
+	}
+
+	private static class Not extends Match {
+		private final Match match;
+		public Not(Match match) {this.match = match;}
+		@Override public boolean match(OsmPrimitive osm) {
+			return !match.match(osm);
+		}
+		@Override public String toString() {return "!"+match;}
+	}
+	
+	private static class And extends Match {
+		private Match lhs;
+		private Match rhs;
+		public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
+		@Override public boolean match(OsmPrimitive osm) {
+			return lhs.match(osm) && rhs.match(osm);
+		}
+		@Override public String toString() {return lhs+" && "+rhs;}
+	}
+	
+	private static class Or extends Match {
+		private Match lhs;
+		private Match rhs;
+		public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
+		@Override public boolean match(OsmPrimitive osm) {
+			return lhs.match(osm) || rhs.match(osm);
+		}
+		@Override public String toString() {return lhs+" || "+rhs;}
+	}
+	
+	private static class Id extends Match {
+		private long id;
+		public Id(long id) {this.id = id;}
+		@Override public boolean match(OsmPrimitive osm) {
+			return osm.id == id;
+		}
+		@Override public String toString() {return "id="+id;}
+	}
+	
+	private static class KeyValue extends Match {
+		private String key;
+		private String value;
+		boolean notValue;
+		public KeyValue(String key, String value, boolean notValue) {this.key = key; this.value = value; this.notValue = notValue;}
+		@Override public boolean match(OsmPrimitive osm) {
+			String value = osm.get(key);
+			if (value == null)
+				return false;
+			return (value.indexOf(this.value) != -1) != notValue;
+		}
+		@Override public String toString() {return key+"="+(notValue?"!":"")+value;}
+	}
+	
+	private static class Any extends Match {
+		private String s;
+		public Any(String s) {this.s = s;}
+		@Override public boolean match(OsmPrimitive osm) {
+			if (osm.keys == null)
+				return s.equals("");
+			for (Entry<String, String> e : osm.keys.entrySet())
+				if (e.getKey().indexOf(s) != -1 || e.getValue().indexOf(s) != -1)
+					return true;
+			return false;
+		}
+		@Override public String toString() {return s;}
+	}
+
+	private static class ExactType extends Match {
+		private String type;
+		public ExactType(String type) {this.type = type;}
+		@Override public boolean match(OsmPrimitive osm) {
+			if (osm instanceof Node)
+				return type.equals("node");
+			if (osm instanceof LineSegment)
+				return type.equals("segment");
+			if (osm instanceof Way)
+				return type.equals("way");
+			throw new IllegalStateException("unknown class "+osm.getClass());
+		}
+		@Override public String toString() {return "type="+type;}
+	}
+
+	
+	public static Match compile(String searchStr) {
+		return new SearchCompiler().parse(new PushbackReader(new StringReader(searchStr)));
+	}
+
+
+	/**
+	 * The token returned is <code>null</code> or starts with an identifier character:
+	 * - for an '-'. This will be the only character
+	 * : for an key. The value is the next token
+	 * | for "OR"
+	 * ' ' for anything else.
+	 * @return The next token in the stream.
+	 */
+	private String nextToken(PushbackReader search) {
+		try {
+			int next;
+			char c = ' ';
+			while (c == ' ' || c == '\t' || c == '\n') {
+				next = search.read();
+				if (next == -1)
+					return null;
+				c = (char)next;
+			}
+			StringBuilder s;
+			switch (c) {
+			case '-':
+				return "-";
+			case '"':
+				s = new StringBuilder("\"");
+				for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read())
+					s.append((char)nc);
+				int nc = search.read();
+				if ((char)nc == ':')
+					return ":"+s.toString();
+				search.unread(nc);
+				return s.toString();
+			default:
+				s = new StringBuilder();
+				for (;;) {
+					s.append(c);
+					next = search.read();
+					if (next == -1) {
+						if (s.toString().equals("OR"))
+							return "|";
+						return " "+s.toString();
+					}
+					c = (char)next;
+					if (c == ' ' || c == '\t' || c == ':' || c == '"') {
+						if (c == ':')
+							return ":"+s.toString();
+						search.unread(next);
+						if (s.toString().equals("OR"))
+							return "|";
+						return " "+s.toString();
+					}
+				}
+			}
+		} catch (IOException e) {
+			throw new RuntimeException(e.getMessage(), e);
+		}		
+	}
+	
+	
+	private boolean notKey = false;
+	private boolean notValue = false;
+	private boolean or = false;
+	private String key = null;
+	String token = null;
+	private Match build() {
+		String value = token.substring(1);
+		if (key == null) {
+			Match c = new Any(value);
+			if (notValue)
+				return new Not(c);
+			return c;
+		}
+		Match c;
+		if (key.equals("type"))
+			c = new ExactType(value);
+		else if (key.equals("id")) {
+			try {
+				c = new Id(Long.parseLong(value));
+			} catch (NumberFormatException x) {
+				c = new Id(0);
+			}
+			if (notValue)
+				c = new Not(c);
+		} else
+			c = new KeyValue(key, value, notValue);
+		if (notKey)
+			return new Not(c);
+		return c;
+	}
+	
+	private Match parse(PushbackReader search) {
+		Match result = null;
+		for (token = nextToken(search); token != null; token = nextToken(search)) {
+			if (token.equals("-"))
+				notValue = true;
+			else if (token.equals("|")) {
+				if (result == null)
+					continue;
+				or = true;
+				notValue = false;
+			} else if (token.startsWith(":")) {
+				if (key == null) {
+					key = token.substring(1);
+					notKey = notValue;
+					notValue = false;
+				} else
+					key += token.substring(1);
+			} else {
+				Match current = build();
+				if (result == null)
+					result = current;
+				else
+					result = or ? new Or(result, current) : new And(result, current);
+				key = null;
+				notKey = false;
+				notValue = false;
+				or = false;
+			}
+		}
+		// if "key:" was the last search
+		if (key != null) {
+			token = " ";
+			Match current = build();
+			result = (result == null) ? current : new And(result, current);
+		}
+		return result == null ? new Always() : result;
+	}
+}
Index: src/org/openstreetmap/josm/tools/UrlLabel.java
===================================================================
--- src/org/openstreetmap/josm/tools/UrlLabel.java	(revision 69)
+++ src/org/openstreetmap/josm/tools/UrlLabel.java	(revision 69)
@@ -0,0 +1,26 @@
+package org.openstreetmap.josm.tools;
+
+import javax.swing.JEditorPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+
+/**
+ * Label that contains a clickable link.
+ * @author Imi
+ */
+public class UrlLabel extends JEditorPane implements HyperlinkListener {
+
+	public UrlLabel(String url) {
+		setContentType("text/html");
+		setText("<html><a href=\""+url+"\">"+url+"</a></html>");
+		setEditable(false);
+		setOpaque(false);
+		addHyperlinkListener(this);
+	}
+
+	public void hyperlinkUpdate(HyperlinkEvent e) {
+		if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+			OpenBrowser.displayUrl("http://wiki.eigenheimstrasse.de/wiki/JOSM");
+		}
+	}
+}
