Merge "Merge branch 'stable-2.5'"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 588a2fc..0a5628a 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -19,9 +19,6 @@
 
 [cache]
   directory = /var/cache/gerrit2
-
-[cache "diff"]
-  diskbuffer = 10 m
 ----
 
 [[accounts]]Section accounts
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
index ebac5a0..f702820 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
@@ -46,31 +46,20 @@
   }
 
   private void refresh() {
-    if (subname == null || "".equals(subname)) {
-      ProjectMap.all(new ScreenLoadCallback<ProjectMap>(this) {
-        @Override
-        protected void preDisplay(final ProjectMap result) {
-          if (subname == null || "".equals(subname)) {
-            display(result);
-          }
-          // Else ignore the result, due to the same reason as below.
+    final String mySubname = subname;
+    ProjectMap.match(subname, new ScreenLoadCallback<ProjectMap>(this) {
+      @Override
+      protected void preDisplay(final ProjectMap result) {
+        if ((mySubname == null && subname == null)
+            || (mySubname != null && mySubname.equals(subname))) {
+          display(result);
         }
-      });
-    } else {
-      final String mySubname = subname;
-      ProjectMap.match(subname, new ScreenLoadCallback<ProjectMap>(this) {
-        @Override
-        protected void preDisplay(final ProjectMap result) {
-          if (mySubname.equals(subname)) {
-            display(result);
-          }
-          // Else ignore the result, the user has already changed subname and
-          // the result is not relevant anymore. If multiple RPC's are fired
-          // the results may come back out-of-order and a non-relevant result
-          // could overwrite the correct result if not ignored.
-        }
-      });
-    }
+        // Else ignore the result, the user has already changed subname and
+        // the result is not relevant anymore. If multiple RPC's are fired
+        // the results may come back out-of-order and a non-relevant result
+        // could overwrite the correct result if not ignored.
+      }
+    });
   }
 
   private void display(final ProjectMap result) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
index 35dfc38..bbeabd3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
@@ -54,11 +54,15 @@
   }
 
   public static void match(String match, AsyncCallback<ProjectMap> cb) {
-    new RestApi("/projects/")
-        .addParameter("m", match)
-        .addParameterRaw("type", "ALL")
-        .addParameterTrue("d") // description
-        .get(NativeMap.copyKeysIntoChildren(cb));
+    if (match == null || "".equals(match)) {
+      all(cb);
+    } else {
+      new RestApi("/projects/")
+          .addParameter("m", match)
+          .addParameterRaw("type", "ALL")
+          .addParameterTrue("d") // description
+          .get(NativeMap.copyKeysIntoChildren(cb));
+    }
   }
 
   protected ProjectMap() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingInlineHyperlink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingInlineHyperlink.java
index 255f823..00825a3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingInlineHyperlink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingInlineHyperlink.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.client.ui;
 
-import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
 public class HighlightingInlineHyperlink extends InlineHyperlink {
 
@@ -34,27 +33,6 @@
   }
 
   private void highlight(final String text, final String toHighlight) {
-    if (toHighlight == null || "".equals(toHighlight)) {
-      return;
-    }
-
-    final SafeHtmlBuilder b = new SafeHtmlBuilder();
-    int pos = 0;
-    int endPos = 0;
-    while ((pos = text.toLowerCase().indexOf(
-        toHighlight.toLowerCase(), pos)) > -1) {
-      if (pos > endPos) {
-        b.append(text.substring(endPos, pos));
-      }
-      endPos = pos + toHighlight.length();
-      b.openElement("b");
-      b.append(text.substring(pos, endPos));
-      b.closeElement("b");
-      pos = endPos;
-    }
-    if (endPos < text.length()) {
-      b.append(text.substring(endPos));
-    }
-    setHTML(b.toSafeHtml().asString());
+    setHTML(Util.highlight(text, toHighlight));
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingProjectsTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingProjectsTable.java
new file mode 100644
index 0000000..fc60360
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HighlightingProjectsTable.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.ui;
+
+import com.google.gerrit.client.projects.ProjectInfo;
+import com.google.gerrit.client.projects.ProjectMap;
+import com.google.gwt.user.client.ui.InlineHTML;
+
+public class HighlightingProjectsTable extends ProjectsTable {
+  private String toHighlight;
+
+  public void display(final ProjectMap projects, final String toHighlight) {
+    this.toHighlight = toHighlight;
+    super.display(projects);
+  }
+
+  @Override
+  protected void populate(final int row, final ProjectInfo k) {
+    table.setWidget(row, 1,
+        new InlineHTML(Util.highlight(k.name(), toHighlight)));
+    table.setText(row, 2, k.description());
+
+    setRowItem(row, k);
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
index a70c3a5..9f0d6af 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
@@ -14,25 +14,34 @@
 
 package com.google.gerrit.client.ui;
 
+import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.account.Util;
 import com.google.gerrit.client.projects.ProjectMap;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.PopupPanel;
 import com.google.gwt.user.client.ui.ScrollPanel;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.HidePopupPanelCommand;
+import com.google.gwtexpui.globalkey.client.NpTextBox;
 import com.google.gwtexpui.user.client.PluginSafeDialogBox;
 
 /** It creates a popup containing all the projects. */
 public class ProjectListPopup {
-  private ProjectsTable projectsTab;
+  private HighlightingProjectsTable projectsTab;
   private PluginSafeDialogBox popup;
+  private NpTextBox filterTxt;
+  private HorizontalPanel filterPanel;
+  private String subname;
   private Button close;
   private ScrollPanel sp;
   private PopupPanel.PositionCallback popupPosition;
@@ -44,6 +53,7 @@
   public void initPopup(final String popupText, final String currentPageLink) {
     createWidgets(popupText, currentPageLink);
     final FlowPanel pfp = new FlowPanel();
+    pfp.add(filterPanel);
     sp = new ScrollPanel(projectsTab);
     sp.setSize("100%", "100%");
     pfp.add(sp);
@@ -90,7 +100,24 @@
 
   private void createWidgets(final String popupText,
       final String currentPageLink) {
-    projectsTab = new ProjectsTable() {
+    filterPanel = new HorizontalPanel();
+    filterPanel.setStyleName(Gerrit.RESOURCES.css().projectFilterPanel());
+    final Label filterLabel =
+        new Label(com.google.gerrit.client.admin.Util.C.projectFilter());
+    filterLabel.setStyleName(Gerrit.RESOURCES.css().projectFilterLabel());
+    filterPanel.add(filterLabel);
+    filterTxt = new NpTextBox();
+    filterTxt.setValue(subname);
+    filterTxt.addKeyUpHandler(new KeyUpHandler() {
+      @Override
+      public void onKeyUp(KeyUpEvent event) {
+        subname = filterTxt.getValue();
+        populateProjects();
+      }
+    });
+    filterPanel.add(filterTxt);
+
+    projectsTab = new HighlightingProjectsTable() {
       @Override
       protected void movePointerTo(final int row, final boolean scroll) {
         super.movePointerTo(row, scroll);
@@ -132,6 +159,7 @@
       }
       projectsTab.setRegisterKeys(true);
       projectsTab.finishDisplay();
+      filterTxt.setFocus(true);
       poppingUp = false;
     }
   }
@@ -146,15 +174,27 @@
   }
 
   protected void populateProjects() {
-    ProjectMap.all(new GerritCallback<ProjectMap>() {
+    final String mySubname = subname;
+    ProjectMap.match(subname, new GerritCallback<ProjectMap>() {
       @Override
       public void onSuccess(final ProjectMap result) {
-        projectsTab.display(result);
-        if (firstPopupLoad) { // Display was delayed until table was loaded
-          firstPopupLoad = false;
-          displayPopup();
+        if ((mySubname == null && subname == null)
+            || (mySubname != null && mySubname.equals(subname))) {
+          display(result);
         }
+        // Else ignore the result, the user has already changed subname and
+        // the result is not relevant anymore. If multiple RPC's are fired
+        // the results may come back out-of-order and a non-relevant result
+        // could overwrite the correct result if not ignored.
       }
     });
   }
+
+  private void display(final ProjectMap result) {
+    projectsTab.display(result, subname);
+    if (firstPopupLoad) { // Display was delayed until table was loaded
+      firstPopupLoad = false;
+      displayPopup();
+    }
+  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java
index 13d0bd9..804eee1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java
@@ -15,8 +15,35 @@
 package com.google.gerrit.client.ui;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
 public class Util {
   public static final UIConstants C = GWT.create(UIConstants.class);
   public static final UIMessages M = GWT.create(UIMessages.class);
+
+  public static String highlight(final String text, final String toHighlight) {
+    final SafeHtmlBuilder b = new SafeHtmlBuilder();
+    if (toHighlight == null || "".equals(toHighlight)) {
+      b.append(text);
+      return b.toSafeHtml().asString();
+    }
+
+    int pos = 0;
+    int endPos = 0;
+    while ((pos = text.toLowerCase().indexOf(
+        toHighlight.toLowerCase(), pos)) > -1) {
+      if (pos > endPos) {
+        b.append(text.substring(endPos, pos));
+      }
+      endPos = pos + toHighlight.length();
+      b.openElement("b");
+      b.append(text.substring(pos, endPos));
+      b.closeElement("b");
+      pos = endPos;
+    }
+    if (endPos < text.length()) {
+      b.append(text.substring(endPos));
+    }
+    return b.toSafeHtml().asString();
+  }
 }