Refactor ProjectListPopup out of MyWatchedProjectsScreen

As a base change or a preparation step for 'On project creation
allow choosing parent from popup.'

Move the code for the ProjectListPopup from MyWatchedProjectsScreen
into its own top-level class so that it can be reused.

Change-Id: I82183d1565c563ed14c4e4abd8713bcdf9c6aebf
Signed-off-by: Bruce Zu <bruce.zu@sonymobile.com>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
index 8d4a767..d38015c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
@@ -15,12 +15,11 @@
 package com.google.gerrit.client.account;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.projects.ProjectMap;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.client.ui.HintTextBox;
+import com.google.gerrit.client.ui.ProjectListPopup;
 import com.google.gerrit.client.ui.ProjectNameSuggestOracle;
-import com.google.gerrit.client.ui.ProjectsTable;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AccountProjectWatchInfo;
 import com.google.gwt.event.dom.client.ClickEvent;
@@ -30,19 +29,13 @@
 import com.google.gwt.event.dom.client.KeyPressHandler;
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
-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.Grid;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.ScrollPanel;
 import com.google.gwt.user.client.ui.SuggestBox;
 import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
 import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.HidePopupPanelCommand;
-import com.google.gwtexpui.user.client.PluginSafeDialogBox;
 
 import java.util.List;
 
@@ -53,15 +46,10 @@
   private HintTextBox filterTxt;
   private MyWatchesTable watchesTab;
   private Button browse;
-  private PluginSafeDialogBox popup;
-  private Button close;
-  private ProjectsTable projectsTab;
   private Button delSel;
-  private PopupPanel.PositionCallback popupPosition;
   private boolean submitOnSelection;
-  private boolean firstPopupLoad = true;
-  private boolean popingUp;
-  private ScrollPanel sp;
+  private Grid grid;
+  private ProjectListPopup projectsPopup;
 
   @Override
   protected void onInitUI() {
@@ -69,7 +57,7 @@
     createWidgets();
 
     /* top table */
-    final Grid grid = new Grid(2, 2);
+    grid = new Grid(2, 2);
     grid.setStyleName(Gerrit.RESOURCES.css().infoBlock());
     grid.setText(0, 0, Util.C.watchedProjectName());
     grid.setWidget(0, 1, nameTxt);
@@ -98,41 +86,22 @@
 
 
     /* popup */
-    final FlowPanel pfp = new FlowPanel();
-    sp = new ScrollPanel(projectsTab);
-    sp.setSize("100%", "100%");
-    pfp.add(sp);
-    pfp.add(close);
-    popup.setWidget(pfp);
-    popup.setHeight("100%");
-    popupPosition = new PopupPanel.PositionCallback() {
+    projectsPopup = new ProjectListPopup() {
+      @Override
+      protected void onMovePointerTo(String projectName) {
+        // prevent user input from being overwritten by simply poping up
+        if (!projectsPopup.isPopingUp() || "".equals(nameBox.getText())) {
+          nameBox.setText(projectName);
+        }
+      }
 
-      public void setPosition(int offsetWidth, int offsetHeight) {
-        int top = grid.getAbsoluteTop() - 50; // under page header
-        // Try to place it to the right of everything else, but not
-        // right justified
-        int left =
-            5 + Math.max(grid.getAbsoluteLeft() + grid.getOffsetWidth(),
-                watchesTab.getAbsoluteLeft() + watchesTab.getOffsetWidth());
-        if (top + offsetHeight > Window.getClientHeight()) {
-          top = Window.getClientHeight() - offsetHeight;
-        }
-        if (left + offsetWidth > Window.getClientWidth()) {
-          left = Window.getClientWidth() - offsetWidth;
-        }
-
-        if (top < 0) {
-          sp.setHeight((sp.getOffsetHeight() + top) + "px");
-          top = 0;
-        }
-        if (left < 0) {
-          sp.setWidth((sp.getOffsetWidth() + left) + "px");
-          left = 0;
-        }
-
-        popup.setPopupPosition(left, top);
+      @Override
+      protected void openRow(String projectName) {
+        nameBox.setText(projectName);
+        doAddNew();
       }
     };
+    projectsPopup.initPopup(Util.C.projects(), PageLinks.SETTINGS_PROJECTS);
   }
 
   protected void createWidgets() {
@@ -185,49 +154,18 @@
       }
     });
 
-    projectsTab = new ProjectsTable() {
-      {
-        keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.projectListOpen()));
-        keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER,
-                                                      Util.C.projectListOpen()));
-      }
-
-      @Override
-      protected void movePointerTo(final int row, final boolean scroll) {
-        super.movePointerTo(row, scroll);
-
-        // prevent user input from being overwritten by simply poping up
-        if (! popingUp || "".equals(nameBox.getText()) ) {
-          nameBox.setText(getRowItem(row).name());
-        }
-      }
-
-      @Override
-      protected void onOpenRow(final int row) {
-        super.onOpenRow(row);
-        nameBox.setText(getRowItem(row).name());
-        doAddNew();
-      }
-    };
-    projectsTab.setSavePointerId(PageLinks.SETTINGS_PROJECTS);
-
-    close = new Button(Util.C.projectsClose());
-    close.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(final ClickEvent event) {
-        closePopup();
-      }
-    });
-
-    popup = new PluginSafeDialogBox();
-    popup.setModal(false);
-    popup.setText(Util.C.projects());
-
     browse = new Button(Util.C.buttonBrowseProjects());
     browse.addClickHandler(new ClickHandler() {
       @Override
       public void onClick(final ClickEvent event) {
-        displayPopup();
+        int top = grid.getAbsoluteTop() - 50; // under page header
+        // Try to place it to the right of everything else, but not
+        // right justified
+        int left =
+            5 + Math.max(grid.getAbsoluteLeft() + grid.getOffsetWidth(),
+                watchesTab.getAbsoluteLeft() + watchesTab.getOffsetWidth());
+        projectsPopup.setPreferredCoordinates(top, left);
+        projectsPopup.displayPopup();
       }
     });
 
@@ -251,27 +189,7 @@
   @Override
   protected void onUnload() {
     super.onUnload();
-    closePopup();
-  }
-
-  protected void displayPopup() {
-    popingUp = true;
-    if (firstPopupLoad) { // For sizing/positioning, delay display until loaded
-      populateProjects();
-    } else {
-      popup.setPopupPositionAndShow(popupPosition);
-
-      GlobalKey.dialog(popup);
-      GlobalKey.addApplication(popup, new HidePopupPanelCommand(0,
-          KeyCodes.KEY_ESCAPE, popup));
-      projectsTab.setRegisterKeys(true);
-      projectsTab.finishDisplay();
-      popingUp = false;
-    }
-  }
-
-  protected void closePopup() {
-    popup.hide();
+    projectsPopup.closePopup();
   }
 
   protected void doAddNew() {
@@ -321,17 +239,4 @@
       }
     });
   }
-
-  protected void populateProjects() {
-    ProjectMap.all(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();
-        }
-      }
-    });
-  }
 }
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
new file mode 100644
index 0000000..217ca5a
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
@@ -0,0 +1,160 @@
+// Copyright (C) 2011 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.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.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.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.user.client.PluginSafeDialogBox;
+
+/** It creates a popup containing all the projects. */
+public class ProjectListPopup {
+  private ProjectsTable projectsTab;
+  private PluginSafeDialogBox popup;
+  private Button close;
+  private ScrollPanel sp;
+  private PopupPanel.PositionCallback popupPosition;
+  private int preferredTop;
+  private int preferredLeft;
+  private boolean popingUp;
+  private boolean firstPopupLoad = true;
+
+  public void initPopup(final String popupText, final String currentPageLink) {
+    createWidgets(popupText, currentPageLink);
+    final FlowPanel pfp = new FlowPanel();
+    sp = new ScrollPanel(projectsTab);
+    sp.setSize("100%", "100%");
+    pfp.add(sp);
+    pfp.add(close);
+    popup.setWidget(pfp);
+    popup.setHeight("100%");
+    popupPosition = getPositionCallback();
+  }
+
+  protected PopupPanel.PositionCallback getPositionCallback() {
+    return new PopupPanel.PositionCallback() {
+      @Override
+      public void setPosition(int offsetWidth, int offsetHeight) {
+        if (preferredTop + offsetHeight > Window.getClientWidth()) {
+          preferredTop = Window.getClientWidth() - offsetHeight;
+        }
+        if (preferredLeft + offsetWidth > Window.getClientWidth()) {
+          preferredLeft = Window.getClientWidth() - offsetWidth;
+        }
+
+        if (preferredTop < 0) {
+          sp.setHeight((sp.getOffsetHeight() + preferredTop) + "px");
+          preferredTop = 0;
+        }
+        if (preferredLeft < 0) {
+          sp.setWidth((sp.getOffsetWidth() + preferredLeft) + "px");
+          preferredLeft = 0;
+        }
+
+        popup.setPopupPosition(preferredLeft, preferredTop);
+      }
+    };
+  }
+
+  protected void onMovePointerTo(String projectName) {
+  }
+
+  protected void openRow(String projectName) {
+  }
+
+  public boolean isPopingUp() {
+    return popingUp;
+  }
+
+  private void createWidgets(final String popupText,
+      final String currentPageLink) {
+    projectsTab = new ProjectsTable() {
+      @Override
+      protected void movePointerTo(final int row, final boolean scroll) {
+        super.movePointerTo(row, scroll);
+        onMovePointerTo(getRowItem(row).name());
+      }
+
+      @Override
+      protected void onOpenRow(final int row) {
+        super.onOpenRow(row);
+        openRow(getRowItem(row).name());
+      }
+    };
+    projectsTab.setSavePointerId(currentPageLink);
+
+    close = new Button(Util.C.projectsClose());
+    close.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        closePopup();
+      }
+    });
+
+    popup = new PluginSafeDialogBox();
+    popup.setModal(false);
+    popup.setText(popupText);
+  }
+
+  public void displayPopup() {
+    popingUp = true;
+    if (firstPopupLoad) { // For sizing/positioning, delay display until loaded
+      populateProjects();
+    } else {
+      popup.setPopupPositionAndShow(popupPosition);
+      GlobalKey.dialog(popup);
+      try {
+        GlobalKey.addApplication(popup, new HidePopupPanelCommand(0,
+            KeyCodes.KEY_ESCAPE, popup));
+      } catch (Throwable e) {
+      }
+      projectsTab.setRegisterKeys(true);
+      projectsTab.finishDisplay();
+      popingUp = false;
+    }
+  }
+
+  public void closePopup() {
+    popup.hide();
+  }
+
+  public void setPreferredCoordinates(final int top, final int left) {
+    this.preferredTop = top;
+    this.preferredLeft = left;
+  }
+
+  protected void populateProjects() {
+    ProjectMap.all(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();
+        }
+      }
+    });
+  }
+}