Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 1212)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 1213)
@@ -450,5 +450,5 @@
         if (args.containsKey("selection"))
             for (String s : args.get("selection"))
-                SearchAction.search(s, SearchAction.SearchMode.add, false);
+                SearchAction.search(s, SearchAction.SearchMode.add, false, false);
     }
 
Index: trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 1212)
+++ trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 1213)
@@ -48,5 +48,5 @@
         SearchSetting s = lastSearch;
         if (s == null)
-            s = new SearchSetting("", false, SearchMode.replace);
+            s = new SearchSetting("", false, false, SearchMode.replace);
         showSearchDialog(s);
     }
@@ -81,4 +81,5 @@
 
         JCheckBox caseSensitive = new JCheckBox(tr("case sensitive"), initialValues.caseSensitive);
+        JCheckBox regexSearch   = new JCheckBox(tr("regular expression"), initialValues.regexSearch);
 
         JPanel p = new JPanel(new GridBagLayout());
@@ -89,4 +90,5 @@
         p.add(remove, GBC.eop());
         p.add(caseSensitive, GBC.eol());
+        p.add(regexSearch, GBC.eol());
         JOptionPane pane = new JOptionPane(p, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null) {
             @Override
@@ -102,5 +104,5 @@
         SearchMode mode = replace.isSelected() ? SearchAction.SearchMode.replace
                 : (add.isSelected() ? SearchAction.SearchMode.add : SearchAction.SearchMode.remove);
-        SearchSetting setting = new SearchSetting(input.getText(), caseSensitive.isSelected(), mode);
+        SearchSetting setting = new SearchSetting(input.getText(), caseSensitive.isSelected(), regexSearch.isSelected(), mode);
         searchWithHistory(setting);
     }
@@ -117,13 +119,13 @@
             searchHistory.removeLast();
         lastSearch = s;
-        search(s.text, s.mode, s.caseSensitive);
+        search(s.text, s.mode, s.caseSensitive, s.regexSearch);
     }
 
     public static void searchWithoutHistory(SearchSetting s) {
         lastSearch = s;
-        search(s.text, s.mode, s.caseSensitive);
+        search(s.text, s.mode, s.caseSensitive, s.regexSearch);
     }
 
-    public static void search(String search, SearchMode mode, boolean caseSensitive) {
+    public static void search(String search, SearchMode mode, boolean caseSensitive, boolean regexSearch) {
         if (search.startsWith("http://") || search.startsWith("ftp://") || search.startsWith("https://")
                 || search.startsWith("file:/")) {
@@ -136,5 +138,5 @@
         try {
             Collection<OsmPrimitive> sel = Main.ds.getSelected();
-            SearchCompiler.Match matcher = SearchCompiler.compile(search, caseSensitive);
+            SearchCompiler.Match matcher = SearchCompiler.compile(search, caseSensitive, regexSearch);
             int foundMatches = 0;
             for (OsmPrimitive osm : Main.ds.allNonDeletedCompletePrimitives()) {
@@ -175,8 +177,10 @@
         SearchMode mode;
         boolean caseSensitive;
+        boolean regexSearch;
 
-        public SearchSetting(String text, boolean caseSensitive, SearchMode mode) {
+        public SearchSetting(String text, boolean caseSensitive, boolean regexSearch, SearchMode mode) {
             super();
             this.caseSensitive = caseSensitive;
+            this.regexSearch = regexSearch;
             this.mode = mode;
             this.text = text;
@@ -186,5 +190,6 @@
         public String toString() {
             String cs = caseSensitive ? tr("CI") : tr("CS");
-            return "\"" + text + "\" (" + cs + ", " + mode + ")";
+            String rx = regexSearch ? (", " + tr("RX")) : "";
+            return "\"" + text + "\" (" + cs + rx + ", " + mode + ")";
         }
 
Index: trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 1212)
+++ trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 1213)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.actions.search;
 
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -7,4 +8,7 @@
 import java.io.StringReader;
 import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
 
 import org.openstreetmap.josm.data.osm.Node;
@@ -21,13 +25,16 @@
 
     private boolean caseSensitive = false;
+    private boolean regexSearch = false;
+    private String  rxErrorMsg = marktr("The regex \"{0}\" had a parse error at offset {1}, full error:\n\n{2}");
     private PushbackTokenizer tokenizer;
 
-    public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) {
+    public SearchCompiler(boolean caseSensitive, boolean regexSearch, PushbackTokenizer tokenizer) {
         this.caseSensitive = caseSensitive;
+        this.regexSearch = regexSearch;
         this.tokenizer = tokenizer;
     }
 
     abstract public static class Match {
-        abstract public boolean match(OsmPrimitive osm);
+        abstract public boolean match(OsmPrimitive osm) throws ParseError;
     }
 
@@ -41,5 +48,5 @@
         private final Match match;
         public Not(Match match) {this.match = match;}
-        @Override public boolean match(OsmPrimitive osm) {
+        @Override public boolean match(OsmPrimitive osm) throws ParseError {
             return !match.match(osm);
         }
@@ -51,5 +58,5 @@
         private Match rhs;
         public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
-        @Override public boolean match(OsmPrimitive osm) {
+        @Override public boolean match(OsmPrimitive osm) throws ParseError {
             return lhs.match(osm) && rhs.match(osm);
         }
@@ -61,5 +68,5 @@
         private Match rhs;
         public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}
-        @Override public boolean match(OsmPrimitive osm) {
+        @Override public boolean match(OsmPrimitive osm) throws ParseError {
             return lhs.match(osm) || rhs.match(osm);
         }
@@ -80,18 +87,80 @@
         private String value;
         public KeyValue(String key, String value) {this.key = key; this.value = value; }
-        @Override public boolean match(OsmPrimitive osm) {
-            String value = null;
-            if (key.equals("timestamp"))
-                value = osm.getTimeStr();
-            else
-                value = osm.get(key);
-            if (value == null)
-                return false;
-            String v1 = caseSensitive ? value : value.toLowerCase();
-            String v2 = caseSensitive ? this.value : this.value.toLowerCase();
-            // is not Java 1.5
-            //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);
-            //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);
-            return v1.indexOf(v2) != -1;
+        @Override public boolean match(OsmPrimitive osm) throws ParseError {
+
+            if (regexSearch) { 
+                if (osm.keys == null)
+                    return false;
+
+                /* The string search will just get a key like
+                 * 'highway' and look that up as osm.get(key). But
+                 * since we're doing a regex match we'll have to loop
+                 * over all the keys to see if they match our regex,
+                 * and only then try to match against the value
+                 */
+
+                Pattern searchKey   = null;
+                Pattern searchValue = null;
+
+                if (caseSensitive) {
+                    try {
+                        searchKey = Pattern.compile(key);
+                    } catch (PatternSyntaxException e) {
+                        throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
+                    }
+                    try {
+                        searchValue = Pattern.compile(value);
+                    } catch (PatternSyntaxException e) {
+                        throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
+                    }
+                } else {
+                    try {
+                        searchKey = Pattern.compile(key, Pattern.CASE_INSENSITIVE);
+                    } catch (PatternSyntaxException e) {
+                        throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
+                    }
+                    try {
+                        searchValue = Pattern.compile(value, Pattern.CASE_INSENSITIVE);
+                    } catch (PatternSyntaxException e) {
+                        throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
+                    }
+                }
+
+                for (Entry<String, String> e : osm.keys.entrySet()) {
+                    String k = e.getKey();
+                    String v = e.getValue();
+
+                    Matcher matcherKey = searchKey.matcher(k);
+                    boolean matchedKey = matcherKey.find();
+
+                    if (matchedKey) {
+                        Matcher matcherValue = searchValue.matcher(v);
+                        boolean matchedValue = matcherValue.find();
+
+                        if (matchedValue)
+                            return true;
+                    }
+                }
+            } else {
+                String value = null;
+
+                if (key.equals("timestamp"))
+                    value = osm.getTimeStr();
+                else
+                    value = osm.get(key);
+
+                if (value == null)
+                    return false;
+
+                String v1 = caseSensitive ? value : value.toLowerCase();
+                String v2 = caseSensitive ? this.value : this.value.toLowerCase();
+
+                // is not Java 1.5
+                //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);
+                //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);
+                return v1.indexOf(v2) != -1;
+            }
+
+            return false;
         }
         @Override public String toString() {return key+"="+value;}
@@ -101,17 +170,58 @@
         private String s;
         public Any(String s) {this.s = s;}
-        @Override public boolean match(OsmPrimitive osm) {
+        @Override public boolean match(OsmPrimitive osm) throws ParseError {
             if (osm.keys == null)
                 return s.equals("");
-            String search = caseSensitive ? s : s.toLowerCase();
+
+            String search;
+            Pattern searchRegex = null;
+
+            if (regexSearch) {
+                search = s;
+                if (caseSensitive) {
+                    try {
+                        searchRegex = Pattern.compile(search);
+                    } catch (PatternSyntaxException e) {
+                        throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
+                    }
+                } else {
+                    try {
+                        searchRegex = Pattern.compile(search, Pattern.CASE_INSENSITIVE);
+                    } catch (PatternSyntaxException e) {
+                        throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
+                    }
+                }
+            } else {
+                search = caseSensitive ? s : s.toLowerCase();
+            }
+
             // is not Java 1.5
             //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC);
             for (Entry<String, String> e : osm.keys.entrySet()) {
-                String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();
-                String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();
-                // is not Java 1.5
-                //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
-                if (key.indexOf(search) != -1 || value.indexOf(search) != -1)
-                    return true;
+                if (regexSearch) {
+                    String key = e.getKey();
+                    String value = e.getValue();
+
+                    // is not Java 1.5
+                    //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
+
+                    Matcher keyMatcher = searchRegex.matcher(key);
+                    Matcher valMatcher = searchRegex.matcher(value);
+
+                    boolean keyMatchFound = keyMatcher.find();
+                    boolean valMatchFound = valMatcher.find();
+
+                    if (keyMatchFound || valMatchFound)
+                        return true;
+                } else {
+                    String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();
+                    String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();
+
+                    // is not Java 1.5
+                    //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);
+
+                    if (key.indexOf(search) != -1 || value.indexOf(search) != -1)
+                        return true;
+                }
             }
             if (osm.user != null) {
@@ -189,7 +299,7 @@
     }
 
-    public static Match compile(String searchStr, boolean caseSensitive)
+    public static Match compile(String searchStr, boolean caseSensitive, boolean regexSearch)
             throws ParseError {
-        return new SearchCompiler(caseSensitive,
+        return new SearchCompiler(caseSensitive, regexSearch,
                 new PushbackTokenizer(
                     new PushbackReader(new StringReader(searchStr))))
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 1212)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 1213)
@@ -200,8 +200,6 @@
         instance.addMouseListener(new MouseAdapter(){
             private void openPopup(MouseEvent e) {
-                Point p = listScrollPane.getMousePosition();
-                if (p == null)
-                    return; // user is faster than swing with mouse movement
-                int index = instance.locationToIndex(e.getPoint());
+                Point p = e.getPoint();
+                int index = instance.locationToIndex(p);
                 Layer layer = (Layer)instance.getModel().getElementAt(index);
                 LayerListPopup menu = new LayerListPopup(instance, layer);
