Merge "Add streamlined workflow to patch screen"
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
index 5b1a25fa..b228cf2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
@@ -233,7 +233,7 @@
    * @param before A string to display at the beginning of the href text
    * @param after A string to display at the end of the href text
    */
-  private PatchLink createLink(int index, PatchScreen.Type patchType,
+  public PatchLink createLink(int index, PatchScreen.Type patchType,
       SafeHtml before, SafeHtml after) {
     Patch patch = patchList.get(index);
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index d76bcca..70dcf75 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -61,7 +61,8 @@
   String previousFileHelp();
   String nextFileHelp();
 
-  String reviewed();
+  String reviewedAnd();
+  String next();
   String download();
 
   String buttonReplyDone();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index 24c4140..694ccb4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -43,7 +43,8 @@
 previousFileHelp = Previous file
 nextFileHelp = Next file
 
-reviewed = Reviewed
+reviewedAnd = Reviewed &
+next = next
 download = (Download)
 
 fileTypeSymlink = Type: Symbolic Link
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index 7089e2b..05d471b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -20,10 +20,13 @@
 import com.google.gerrit.client.RpcStatus;
 import com.google.gerrit.client.changes.CommitMessageBlock;
 import com.google.gerrit.client.changes.PatchTable;
+import com.google.gerrit.client.changes.PatchTable.PatchValidator;
 import com.google.gerrit.client.changes.Util;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
+import com.google.gerrit.client.ui.ChangeLink;
 import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
+import com.google.gerrit.client.ui.PatchLink;
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchSetDetail;
@@ -34,17 +37,22 @@
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.CheckBox;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
+import com.google.gwtexpui.safehtml.client.SafeHtml;
+import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 import com.google.gwtjsonrpc.common.VoidResult;
 
 public abstract class PatchScreen extends Screen implements
@@ -102,7 +110,8 @@
   protected PatchScriptSettingsPanel settingsPanel;
   protected TopView topView;
 
-  private CheckBox reviewed;
+  private CheckBox reviewedCheckBox;
+  private FlowPanel reviewedPanel;
   private HistoryTable historyTable;
   private FlowPanel topPanel;
   private FlowPanel contentPanel;
@@ -144,14 +153,7 @@
     idSideB = id.getParentKey();
     this.patchIndex = patchIndex;
 
-    reviewed = new CheckBox(Util.C.reviewed());
-    reviewed.addValueChangeHandler(
-        new ValueChangeHandler<Boolean>() {
-          @Override
-          public void onValueChange(ValueChangeEvent<Boolean> event) {
-            setReviewedByCurrentUser(event.getValue());
-          }
-        });
+    createReviewedPanel();
 
     prefs = fileList != null ? fileList.getPreferences() :
                                new ListenableAccountDiffPreference();
@@ -169,6 +171,71 @@
     settingsPanel = new PatchScriptSettingsPanel(prefs);
   }
 
+  private void createReviewedPanel(){
+    reviewedPanel = new FlowPanel();
+
+    reviewedCheckBox = new CheckBox(PatchUtil.C.reviewedAnd() + " ");
+    reviewedCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+      @Override
+      public void onValueChange(ValueChangeEvent<Boolean> event) {
+        setReviewedByCurrentUser(event.getValue());
+      }
+    });
+
+    reviewedPanel.add(reviewedCheckBox);
+    reviewedPanel.add(getReviewedAnchor());
+  }
+
+  private Anchor getReviewedAnchor() {
+    SafeHtmlBuilder text = new SafeHtmlBuilder();
+    text.append(PatchUtil.C.next());
+    text.append(SafeHtml.asis(Util.C.nextPatchLinkIcon()));
+
+    Anchor reviewedAnchor = new Anchor("");
+    SafeHtml.set(reviewedAnchor, text);
+
+    reviewedAnchor.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        setReviewedByCurrentUser(true);
+      }
+    });
+
+    final PatchValidator unreviewedValidator = new PatchValidator() {
+      public boolean isValid(Patch patch) {
+        return !patch.isReviewedByCurrentUser();
+      }
+    };
+
+    int nextUnreviewedPatchIndex =
+        fileList.getNextPatch(patchIndex, true, unreviewedValidator,
+            fileList.PREFERENCE_VALIDATOR);
+
+    if (nextUnreviewedPatchIndex > -1) {
+      // Create invisible patch link to change page
+      final PatchLink reviewedLink =
+          fileList.createLink(nextUnreviewedPatchIndex, getPatchScreenType(),
+              null, null);
+      reviewedLink.setText("");
+      reviewedAnchor.addClickHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          reviewedLink.go();
+        }
+      });
+    } else {
+      final ChangeLink upLink = new ChangeLink("", patchKey.getParentKey());
+      reviewedAnchor.addClickHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          upLink.go();
+        }
+      });
+    }
+
+    return reviewedAnchor;
+  }
+
   @Override
   public void notifyDraftDelta(int delta) {
     lastScript = null;
@@ -181,9 +248,9 @@
 
   private void update(AccountDiffPreference dp) {
     // Did the user just turn on auto-review?
-    if (!reviewed.getValue() && prefs.getOld().isManualReview()
+    if (!reviewedCheckBox.getValue() && prefs.getOld().isManualReview()
         && !dp.isManualReview()) {
-      reviewed.setValue(true);
+      reviewedCheckBox.setValue(true);
       setReviewedByCurrentUser(true);
     }
 
@@ -237,7 +304,7 @@
     super.onInitUI();
 
     if (Gerrit.isSignedIn()) {
-      setTitleFarEast(reviewed);
+      setTitleFarEast(reviewedPanel);
     }
 
     keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
@@ -474,7 +541,7 @@
           }
         }
       }
-      reviewed.setValue(isReviewed);
+      reviewedCheckBox.setValue(isReviewed);
     }
 
     intralineFailure = isFirst && script.hasIntralineFailure();