Merge doc and change searches.

This CL puts a dropdown in the SearchPanel, to choose from changes
search (default) or documentation search.

I mostly copied the css for the search button to the dropdown, with
some minor changes.

If docs are not available (e.g. built without docs), the whole dropdown
will be gone and it should be the same as before.

Screenshot: https://i.imgur.com/Qyg2VZg.png

Change-Id: I04e15327f43fc9c8002cba364b44d77f52075234
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index b1b795c..3a64dc0 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -115,6 +115,7 @@
     "gerrit": {
       "all_projects": "All-Projects",
       "all_users": "All-Users"
+      "doc_search": true
     },
     "sshd": {},
     "suggest": {
@@ -1189,6 +1190,8 @@
 |`all_users_name`    ||
 Name of the link:config-gerrit.html#gerrit.allUsers[project in which
 meta data of all users is stored].
+|`doc_search`        ||
+Whether documentation search is available.
 |`doc_url`           |optional|
 Custom base URL where Gerrit server documentation is located.
 (Documentation may still be available at /Documentation relative to the
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
index 28e0d24..b6cd45f 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
@@ -49,6 +49,7 @@
   public static final String ADMIN_CREATE_PROJECT = "/admin/create-project/";
   public static final String ADMIN_PLUGINS = "/admin/plugins/";
   public static final String MY_GROUPS = "/groups/self";
+  public static final String DOCUMENTATION = "/Documentation/";
 
   public static String toChange(final ChangeInfo c) {
     return toChange(c.getId());
@@ -140,6 +141,10 @@
     return SETTINGS_EXTENSION + pluginName + "/" + path;
   }
 
+  public static String toDocumentationQuery(String query) {
+    return DOCUMENTATION + KeyUtil.encode(query);
+  }
+
   private static String status(Status status) {
     switch (status) {
       case ABANDONED:
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GerritInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GerritInfo.java
index 55ef892..750412d 100644
--- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GerritInfo.java
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/GerritInfo.java
@@ -36,6 +36,7 @@
 
   public final native String allProjects() /*-{ return this.all_projects; }-*/;
   public final native String allUsers() /*-{ return this.all_users; }-*/;
+  public final native boolean docSearch() /*-{ return this.doc_search; }-*/;
   public final native String docUrl() /*-{ return this.doc_url; }-*/;
   public final native boolean editGpgKeys() /*-{ return this.edit_gpg_keys || false; }-*/;
   public final native String reportBugUrl() /*-{ return this.report_bug_url; }-*/;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index 3b58ac0..139b9c0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -118,6 +118,7 @@
   private static AccountPreferencesInfo myPrefs;
   private static UrlAliasMatcher urlAliasMatcher;
   private static boolean hasDocumentation;
+  private static boolean docSearch;
   private static String docUrl;
   private static HostPageData.Theme myTheme;
   private static String defaultScreenToken;
@@ -487,6 +488,7 @@
           hasDocumentation = true;
           docUrl = du;
         }
+        docSearch = info.gerrit().docSearch();
       }
     }));
     HostPageDataService hpd = GWT.create(HostPageDataService.class);
@@ -918,6 +920,10 @@
     urlAliasMatcher.updateUserAliases(myPrefs.urlAliases());
   }
 
+  public static boolean hasDocSearch() {
+    return docSearch;
+  }
+
   private static void getDocIndex(final AsyncCallback<DocInfo> cb) {
     RequestBuilder req =
         new RequestBuilder(RequestBuilder.HEAD, GWT.getHostPageBaseURL()
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index 269999c..6802a0d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -126,4 +126,7 @@
   String stringListPanelDelete();
   String stringListPanelUp();
   String stringListPanelDown();
+
+  String searchDropdownChanges();
+  String searchDropdownDoc();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index fb74506..1337b31 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -109,3 +109,6 @@
 stringListPanelDelete = Delete
 stringListPanelUp = Up
 stringListPanelDown = Down
+
+searchDropdownChanges = Changes
+searchDropdownDoc = Documentation
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
index 45b1d52..83a187b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
@@ -27,6 +27,7 @@
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.ListBox;
 import com.google.gwt.user.client.ui.SuggestBox;
 import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
@@ -34,6 +35,7 @@
 
 class SearchPanel extends Composite {
   private final HintTextBox searchBox;
+  private final ListBox dropdown;
   private HandlerRegistration regFocus;
 
   SearchPanel() {
@@ -54,6 +56,18 @@
       }
     });
 
+    if (Gerrit.hasDocSearch()) {
+      dropdown = new ListBox();
+      dropdown.setStyleName("searchDropdown");
+      dropdown.addItem(Gerrit.C.searchDropdownChanges());
+      dropdown.addItem(Gerrit.C.searchDropdownDoc());
+      dropdown.setVisibleItemCount(1);
+      dropdown.setSelectedIndex(0);
+    } else {
+      // Doc search is NOT available.
+      dropdown = null;
+    }
+
     final SuggestBox suggestBox =
         new SuggestBox(new SearchSuggestOracle(), searchBox, suggestionDisplay);
     searchBox.setStyleName("searchTextBox");
@@ -70,6 +84,9 @@
     });
 
     body.add(suggestBox);
+    if (dropdown != null) {
+      body.add(dropdown);
+    }
     body.add(searchButton);
   }
 
@@ -110,14 +127,23 @@
 
     searchBox.setFocus(false);
 
-    if (query.matches("^[1-9][0-9]*$")) {
-      Gerrit.display(PageLinks.toChange(Change.Id.parse(query)));
+    if (dropdown != null
+        && dropdown.getSelectedValue().equals(Gerrit.C.searchDropdownDoc())) {
+      // doc
+      Gerrit.display(PageLinks.toDocumentationQuery(query));
     } else {
-      Gerrit.display(PageLinks.toChangeQuery(query), QueryScreen.forQuery(query));
+      // changes
+      if (query.matches("^[1-9][0-9]*$")) {
+        Gerrit.display(PageLinks.toChange(Change.Id.parse(query)));
+      } else {
+        Gerrit.display(
+            PageLinks.toChangeQuery(query), QueryScreen.forQuery(query));
+      }
     }
   }
 
-  private static class MySuggestionDisplay extends SuggestBox.DefaultSuggestionDisplay {
+  private static class MySuggestionDisplay
+      extends SuggestBox.DefaultSuggestionDisplay {
     private boolean isSuggestionSelected;
 
     private MySuggestionDisplay() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 0987e83..3c9a8b9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -307,7 +307,15 @@
 }
 .searchPanel .searchTextBox {
   font-size: 9pt;
-  margin: 5.286px 3px 0 0;
+  margin: 8.286px 3px 0 0;
+}
+.searchPanel .searchDropdown {
+  font-size: 8pt;
+  border: 2px solid;
+  border-color: rgba(0, 0, 0, 0.15);
+  height: 16px;
+  border-radius: 2px;
+  box-sizing: content-box;
 }
 .searchPanel .searchButton {
   text-align: center;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
index 9eca842..e5ac370 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java
@@ -35,6 +35,7 @@
 import com.google.gerrit.server.change.ArchiveFormat;
 import com.google.gerrit.server.change.GetArchive;
 import com.google.gerrit.server.change.Submit;
+import com.google.gerrit.server.documentation.QueryDocumentationExecutor;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.Config;
@@ -64,6 +65,7 @@
   private final GitwebConfig gitwebConfig;
   private final DynamicItem<AvatarProvider> avatar;
   private final boolean enableSignedPush;
+  private final QueryDocumentationExecutor docSearcher;
 
   @Inject
   public GetServerInfo(
@@ -79,7 +81,8 @@
       @AnonymousCowardName String anonymousCowardName,
       GitwebConfig gitwebConfig,
       DynamicItem<AvatarProvider> avatar,
-      @EnableSignedPush boolean enableSignedPush) {
+      @EnableSignedPush boolean enableSignedPush,
+      QueryDocumentationExecutor docSearcher) {
     this.config = config;
     this.authConfig = authConfig;
     this.realm = realm;
@@ -93,6 +96,7 @@
     this.gitwebConfig = gitwebConfig;
     this.avatar = avatar;
     this.enableSignedPush = enableSignedPush;
+    this.docSearcher = docSearcher;
   }
 
   @Override
@@ -238,6 +242,7 @@
     info.reportBugUrl = cfg.getString("gerrit", null, "reportBugUrl");
     info.reportBugText = cfg.getString("gerrit", null, "reportBugText");
     info.docUrl = getDocUrl(cfg);
+    info.docSearch = docSearcher.isAvailable();
     info.editGpgKeys = toBoolean(enableSignedPush
         && cfg.getBoolean("gerrit", null, "editGpgKeys", true));
     return info;
@@ -366,10 +371,11 @@
   public static class GerritInfo {
     public String allProjects;
     public String allUsers;
+    public Boolean docSearch;
     public String docUrl;
+    public Boolean editGpgKeys;
     public String reportBugUrl;
     public String reportBugText;
-    public Boolean editGpgKeys;
   }
 
   public static class GitwebInfo {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java b/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
index 446013e..438795f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
@@ -74,7 +74,7 @@
   }
 
   public List<DocResult> doQuery(String q) throws DocQueryException {
-    if (parser == null || searcher == null) {
+    if (!isAvailable()) {
       throw new DocQueryException("Documentation search not available");
     }
     try {
@@ -123,6 +123,10 @@
     return dir;
   }
 
+  public boolean isAvailable() {
+    return parser != null && searcher != null;
+  }
+
   @SuppressWarnings("serial")
   public static class DocQueryException extends Exception {
     DocQueryException() {