Index: trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 4831)
+++ trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 4832)
@@ -8,9 +8,13 @@
 
 import java.awt.Dimension;
+import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -26,4 +30,6 @@
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.text.BadLocationException;
 
 import org.openstreetmap.josm.Main;
@@ -42,4 +48,5 @@
 import org.openstreetmap.josm.tools.Property;
 import org.openstreetmap.josm.tools.Shortcut;
+import org.openstreetmap.josm.tools.Utils;
 
 public class SearchAction extends JosmAction implements ParameterizedAction {
@@ -151,4 +158,45 @@
         public String toString() {
             return s.toString();
+        }
+    }
+
+    private static class SearchKeywordRow extends JPanel {
+
+        private final HistoryComboBox hcb;
+
+        public SearchKeywordRow(HistoryComboBox hcb) {
+            super(new FlowLayout(FlowLayout.LEFT));
+            this.hcb = hcb;
+        }
+
+        public SearchKeywordRow addTitle(String title) {
+            add(new JLabel(tr("{0}: ", title)));
+            return this;
+        }
+
+        public SearchKeywordRow addKeyword(String displayText, final String insertText, String description, String... examples) {
+            JLabel label = new JLabel("<html><style>td{border:1px solid gray;}</style><table><tr><td>" + displayText + "</td></tr></table></html>");
+            add(label);
+            if (description != null || examples.length > 0) {
+                label.setToolTipText("<html>"
+                        + description
+                        + (examples.length > 0 ? ("<ul><li>" + Utils.join("</li><li>", Arrays.asList(examples)) + "</li></ul>") : "")
+                        + "</html>");
+            }
+            if (insertText != null) {
+                label.addMouseListener(new MouseAdapter() {
+
+                    @Override
+                    public void mouseClicked(MouseEvent e) {
+                        try {
+                            JTextField tf = (JTextField) hcb.getEditor().getEditorComponent();
+                            tf.getDocument().insertString(tf.getCaretPosition(), " " + insertText, null);
+                        } catch (BadLocationException ex) {
+                            throw new RuntimeException(ex.getMessage(), ex);
+                        }
+                    }
+                });
+            }
+            return this;
         }
     }
@@ -188,5 +236,5 @@
         allElements.setToolTipText(tr("Also include incomplete and deleted objects in search."));
         final JCheckBox regexSearch   = new JCheckBox(tr("regular expression"), initialValues.regexSearch);
-        final JCheckBox addOnToolbar  = new JCheckBox(tr("Add toolbar button"), false); 
+        final JCheckBox addOnToolbar  = new JCheckBox(tr("add toolbar button"), false);
 
         JPanel top = new JPanel(new GridBagLayout());
@@ -206,5 +254,78 @@
         }
 
-        JPanel right = new JPanel();
+        final JPanel right;
+        if (Main.pref.getBoolean("dialog.search.new", false)) {
+            right = new JPanel(new GridBagLayout());
+            buildHintsNew(right, hcbSearchString);
+        } else {
+            right = new JPanel();
+            buildHints(right);
+        }
+
+        final JPanel p = new JPanel(new GridBagLayout());
+        p.add(top, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 0));
+        p.add(left, GBC.std().anchor(GBC.NORTH).insets(5, 10, 10, 0));
+        p.add(right, GBC.eol());
+        ExtendedDialog dialog = new ExtendedDialog(
+                Main.parent,
+                initialValues instanceof Filter ? tr("Filter") : tr("Search"),
+                        new String[] {
+                    initialValues instanceof Filter ? tr("Submit filter") : tr("Start Search"),
+                            tr("Cancel")}
+        ) {
+            @Override
+            protected void buttonAction(int buttonIndex, ActionEvent evt) {
+                if (buttonIndex == 0) {
+                    try {
+                        SearchCompiler.compile(hcbSearchString.getText(), caseSensitive.isSelected(), regexSearch.isSelected());
+                        super.buttonAction(buttonIndex, evt);
+                    } catch (ParseError e) {
+                        JOptionPane.showMessageDialog(
+                                Main.parent,
+                                tr("Search expression is not valid: \n\n {0}", e.getMessage()),
+                                tr("Invalid search expression"),
+                                JOptionPane.ERROR_MESSAGE);
+                    }
+                } else {
+                    super.buttonAction(buttonIndex, evt);
+                }
+            }
+        };
+        dialog.setButtonIcons(new String[] {"dialogs/search.png", "cancel.png"});
+        dialog.configureContextsensitiveHelp("/Action/Search", true /* show help button */);
+        dialog.setContent(p);
+        dialog.showDialog();
+        int result = dialog.getValue();
+
+        if(result != 1) return null;
+
+        // User pressed OK - let's perform the search
+        SearchMode mode = replace.isSelected() ? SearchAction.SearchMode.replace
+                : (add.isSelected() ? SearchAction.SearchMode.add
+                        : (remove.isSelected() ? SearchAction.SearchMode.remove : SearchAction.SearchMode.in_selection));
+        initialValues.text = hcbSearchString.getText();
+        initialValues.mode = mode;
+        initialValues.caseSensitive = caseSensitive.isSelected();
+        initialValues.allElements = allElements.isSelected();
+        initialValues.regexSearch = regexSearch.isSelected();
+        
+        if (addOnToolbar.isSelected()) {
+            ToolbarPreferences.ActionDefinition aDef = 
+                    new ToolbarPreferences.ActionDefinition(Main.main.menu.search);
+            aDef.getParameters().put("searchExpression", initialValues);
+            // parametrized action definition is now composed
+            ActionParser actionParser = new ToolbarPreferences.ActionParser(null);
+            String res = actionParser.saveAction(aDef);
+            
+            Collection<String> t = new LinkedList<String>(ToolbarPreferences.getToolString());
+            // add custom search button to toolbar preferences
+            if (!t.contains(res)) t.add(res);
+            Main.pref.putCollection("toolbar", t);
+            Main.toolbar.refreshToolbarControl();
+        }
+        return initialValues;
+    }
+
+    private static void buildHints(JPanel right) {
         DescriptionTextBuilder descriptionText = new DescriptionTextBuilder();
         descriptionText.append("<html><style>li.header{font-size:110%; list-style-type:none; margin-top:5px;}</style><ul>");
@@ -251,67 +372,74 @@
         description.setFont(description.getFont().deriveFont(Font.PLAIN));
         right.add(description);
-
-        final JPanel p = new JPanel(new GridBagLayout());
-        p.add(top, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 0));
-        p.add(left, GBC.std().anchor(GBC.NORTH).insets(5, 10, 10, 0));
-        p.add(right, GBC.eol());
-        ExtendedDialog dialog = new ExtendedDialog(
-                Main.parent,
-                initialValues instanceof Filter ? tr("Filter") : tr("Search"),
-                        new String[] {
-                    initialValues instanceof Filter ? tr("Submit filter") : tr("Start Search"),
-                            tr("Cancel")}
-        ) {
-            @Override
-            protected void buttonAction(int buttonIndex, ActionEvent evt) {
-                if (buttonIndex == 0) {
-                    try {
-                        SearchCompiler.compile(hcbSearchString.getText(), caseSensitive.isSelected(), regexSearch.isSelected());
-                        super.buttonAction(buttonIndex, evt);
-                    } catch (ParseError e) {
-                        JOptionPane.showMessageDialog(
-                                Main.parent,
-                                tr("Search expression is not valid: \n\n {0}", e.getMessage()),
-                                tr("Invalid search expression"),
-                                JOptionPane.ERROR_MESSAGE);
-                    }
-                } else {
-                    super.buttonAction(buttonIndex, evt);
-                }
-            }
-        };
-        dialog.setButtonIcons(new String[] {"dialogs/search.png", "cancel.png"});
-        dialog.configureContextsensitiveHelp("/Action/Search", true /* show help button */);
-        dialog.setContent(p);
-        dialog.showDialog();
-        int result = dialog.getValue();
-
-        if(result != 1) return null;
-
-        // User pressed OK - let's perform the search
-        SearchMode mode = replace.isSelected() ? SearchAction.SearchMode.replace
-                : (add.isSelected() ? SearchAction.SearchMode.add
-                        : (remove.isSelected() ? SearchAction.SearchMode.remove : SearchAction.SearchMode.in_selection));
-        initialValues.text = hcbSearchString.getText();
-        initialValues.mode = mode;
-        initialValues.caseSensitive = caseSensitive.isSelected();
-        initialValues.allElements = allElements.isSelected();
-        initialValues.regexSearch = regexSearch.isSelected();
-        
-        if (addOnToolbar.isSelected()) {
-            ToolbarPreferences.ActionDefinition aDef = 
-                    new ToolbarPreferences.ActionDefinition(Main.main.menu.search);
-            aDef.getParameters().put("searchExpression", initialValues);
-            // parametrized action definition is now composed
-            ActionParser actionParser = new ToolbarPreferences.ActionParser(null);
-            String res = actionParser.saveAction(aDef);
-            
-            Collection<String> t = new LinkedList<String>(ToolbarPreferences.getToolString());
-            // add custom search button to toolbar preferences
-            if (!t.contains(res)) t.add(res);
-            Main.pref.putCollection("toolbar", t);
-            Main.toolbar.refreshToolbarControl();
-        }
-        return initialValues;
+    }
+
+    private static void buildHintsNew(JPanel right, HistoryComboBox hcbSearchString) {
+        right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("basic examples"))
+                .addKeyword("Baker Street", "Baker Street", tr("''Baker'' and ''Street'' in any key"))
+                .addKeyword("\"Baker Street\"", "\"Baker Street\"", tr("''Baker Street'' in any key"))
+                , GBC.eol());
+        right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("basics"))
+                .addKeyword("<i>key</i>:<i>valuefragment</i>", null, tr("''valuefragment'' anywhere in ''key''"), "name:str matches name=Bakerstreet")
+                .addKeyword("-<i>key</i>:<i>valuefragment</i>", null, tr("''valuefragment'' nowhere in ''key''"))
+                .addKeyword("<i>key</i>=<i>value</i>", null, tr("''key'' with exactly ''value''"))
+                .addKeyword("<i>key</i>=*", null, tr("''key'' with any value"))
+                .addKeyword("*=<i>value</i>", null, tr("''value'' in any key"))
+                .addKeyword("<i>key</i>=", null, tr("matches if ''key'' exists"))
+                , GBC.eol());
+        right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("combinators"))
+                .addKeyword("<i>expr</i> <i>expr</i>", null, tr("logical and (both expressions have to be satisfied)"))
+                .addKeyword("<i>expr</i> | <i>expr</i>", "| ", tr("logical or (at least one expression has to be satisfied)"))
+                .addKeyword("<i>expr</i> OR <i>expr</i>", "OR ", tr("logical or (at least one expression has to be satisfied)"))
+                .addKeyword("-<i>expr</i>", null, tr("logical not"))
+                .addKeyword("(<i>expr</i>)", null, tr("use parenthesis to group expressions"))
+                .addKeyword("\"key\"=\"value\"", null, tr("to quote operators.<br>Within quoted strings the <b>\"</b> and <b>\\</b> characters need to be escaped by a preceding <b>\\</b> (e.g. <b>\\\"</b> and <b>\\\\</b>)."), "\"addr:street\"")
+                , GBC.eol());
+
+        if (Main.pref.getBoolean("expert", false)) {
+            right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("objects"))
+                .addKeyword("type:node", "type:node ", tr("all ways"))
+                .addKeyword("type:way", "type:way ", tr("all ways"))
+                .addKeyword("type:relation", "type:relation ", tr("all relations"))
+                .addKeyword("closed", "closed ", tr("all closed ways"))
+                , GBC.eol());
+            right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("metadata"))
+                .addKeyword("user:", "user:", tr("objects changed by user", "user:anonymous"))
+                .addKeyword("id:", "id:", tr("objects with given ID"), "id:0 (new objects)")
+                .addKeyword("version:", "version:", tr("objects with given version"), "version:0 (objects without an assigned version)")
+                .addKeyword("changeset:", "changeset:", tr("objects with given changeset ID"), "changeset:0 (objects without an assigned changeset)")
+                .addKeyword("timestamp:", "timestamp:", tr("objects with last modification timestamp within range"), "timestamp:2012/", "timestamp:2008/2011-02-04T12")
+                , GBC.eol());
+            right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("properties"))
+                .addKeyword("nodes:<i>20-</i>", "nodes:", tr("objects with at least 20 nodes"))
+                .addKeyword("tags:<i>5-10</i>", "tags:", tr("objects having 5 to 10 tags"))
+                .addKeyword("role:", "role:", tr("objects with given role in a relation"))
+                .addKeyword("areasize:<i>-100</i>", "areasize:", tr("closed ways with an area of 100 m\u00b2"))
+                , GBC.eol());
+            right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("state"))
+                .addKeyword("modified", "modified ", tr("all modified objects"))
+                .addKeyword("new", "new ", tr("all new objects"))
+                .addKeyword("selected", "selected ", tr("all selected objects"))
+                .addKeyword("incomplete", "incomplete ", tr("all incomplete objects"))
+                , GBC.eol());
+            right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("relations"))
+                .addKeyword("child <i>expr</i>", "child ", tr("all children of objects matching the expression"), "child building")
+                .addKeyword("parent <i>expr</i>", "parent ", tr("all parents of objects matching the expression"), "parent bus_stop")
+                , GBC.eol());
+            right.add(new SearchKeywordRow(hcbSearchString)
+                .addTitle(tr("view"))
+                .addKeyword("inview", "inview ", tr("objects in current view"))
+                .addKeyword("allinview", "allinview ", tr("objects (and all its way nodes / relation members) in current view"))
+                .addKeyword("indownloadedarea", "indownloadedarea ", tr("objects in downloaded area"))
+                .addKeyword("allindownloadedarea", "allindownloadedarea ", tr("objects (and all its way nodes / relation members) in downloaded area"))
+                , GBC.eol());
+        }
     }
 
