Add edit icon to preview diff screens

Change-Id: Ia5e98faea325a33343d45f53762273b3054fd362
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java
index 83ea13a..38c4cf9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeInfo.java
@@ -25,9 +25,28 @@
 public class ChangeInfo extends JavaScriptObject {
   public final native String project() /*-{ return this.project; }-*/;
   public final native NativeMap<RevisionInfo> revisions() /*-{ return this.revisions; }-*/;
-  public final native int _number() /*-{ return this._number; }-*/;
-  public final native String current_revision() /*-{ return this.current_revision; }-*/;
   public final native RevisionInfo revision(String n) /*-{ return this.revisions[n]; }-*/;
+  public final native int _number() /*-{ return this._number; }-*/;
+  private final native String statusRaw() /*-{ return this.status; }-*/;
+  public final native String current_revision() /*-{ return this.current_revision; }-*/;
+  public final native void set_edit(EditInfo edit) /*-{ this.edit = edit; }-*/;
+  public final native EditInfo edit() /*-{ return this.edit; }-*/;
+  public final native boolean has_edit() /*-{ return this.hasOwnProperty('edit') }-*/;
+
+  public final ChangeStatus getStatus() {
+    return ChangeStatus.valueOf(statusRaw());
+  }
+
+  public final boolean isOpen() {
+    switch (getStatus()) {
+      case NEW:
+      case SUBMITTED:
+      case DRAFT:
+        return true;
+      default:
+        return false;
+    }
+  }
 
   protected ChangeInfo() {
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeStatus.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeStatus.java
new file mode 100644
index 0000000..ed789cc
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/ChangeStatus.java
@@ -0,0 +1,101 @@
+// Copyright (C) 2014 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.googlesource.gerrit.plugins.xdocs.client;
+
+/* Current state within the basic workflow of the change **/
+public enum ChangeStatus {
+
+  /**
+   * Change is open and pending review, or review is in progress.
+   *
+   * <p>
+   * This is the default state assigned to a change when it is first created
+   * in the database. A change stays in the NEW state throughout its review
+   * cycle, until the change is submitted or abandoned.
+   *
+   * <p>
+   * Changes in the NEW state can be moved to:
+   * <ul>
+   * <li>{@link #SUBMITTED} - when the Submit Patch Set action is used;
+   * <li>{@link #ABANDONED} - when the Abandon action is used.
+   * </ul>
+   */
+  NEW,
+
+  /**
+   * Change is open, but has been submitted to the merge queue.
+   *
+   * <p>
+   * A change enters the SUBMITTED state when an authorized user presses the
+   * "submit" action through the web UI, requesting that Gerrit merge the
+   * change's current patch set into the destination branch.
+   *
+   * <p>
+   * Typically a change resides in the SUBMITTED for only a brief sub-second
+   * period while the merge queue fires and the destination branch is updated.
+   * However, if a dependency commit (directly or transitively) is not yet
+   * merged into the branch, the change will hang in the SUBMITTED state
+   * indefinitely.
+   *
+   * <p>
+   * Changes in the SUBMITTED state can be moved to:
+   * <ul>
+   * <li>{@link #NEW} - when a replacement patch set is supplied, OR when a
+   * merge conflict is detected;
+   * <li>{@link #MERGED} - when the change has been successfully merged into
+   * the destination branch;
+   * <li>{@link #ABANDONED} - when the Abandon action is used.
+   * </ul>
+   */
+  SUBMITTED,
+
+  /**
+   * Change is a draft change that only consists of draft patchsets.
+   *
+   * <p>
+   * This is a change that is not meant to be submitted or reviewed yet. If
+   * the uploader publishes the change, it becomes a NEW change.
+   * Publishing is a one-way action, a change cannot return to DRAFT status.
+   * Draft changes are only visible to the uploader and those explicitly
+   * added as reviewers.
+   *
+   * <p>
+   * Changes in the DRAFT state can be moved to:
+   * <ul>
+   * <li>{@link #NEW} - when the change is published, it becomes a new change;
+   * </ul>
+   */
+  DRAFT,
+
+  /**
+   * Change is closed, and submitted to its destination branch.
+   *
+   * <p>
+   * Once a change has been merged, it cannot be further modified by adding a
+   * replacement patch set. Draft comments however may be published,
+   * supporting a post-submit review.
+   */
+  MERGED,
+
+  /**
+   * Change is closed, but was not submitted to its destination branch.
+   *
+   * <p>
+   * Once a change has been abandoned, it cannot be further modified by adding
+   * a replacement patch set, and it cannot be merged. Draft comments however
+   * may be published, permitting reviewers to send constructive feedback.
+   */
+  ABANDONED
+}
\ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/PatchSetSelectBox.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/PatchSetSelectBox.java
index c895091..21190a2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/PatchSetSelectBox.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/PatchSetSelectBox.java
@@ -82,6 +82,10 @@
     if (!COMMIT_MSG.equals(path)) {
       add(createDownloadLink());
     }
+
+    if (showEditIcon()) {
+      add(createEditIcon());
+    }
   }
 
   private void addPatchSetLabel() {
@@ -145,6 +149,26 @@
     return anchor;
   }
 
+  private boolean showEditIcon() {
+    if (sideA() || !change.isOpen() || !Plugin.get().isSignedIn()) {
+      return false;
+    }
+
+    if (change.has_edit()) {
+      return patchSet == 0;
+    } else {
+      return patchSet == change.revision(change.current_revision())._number();
+    }
+  }
+
+  private Anchor createEditIcon() {
+    Anchor anchor = new Anchor(
+        new ImageResourceRenderer().render(XDocsPlugin.RESOURCES.edit()),
+        "#" + getEditUrl(change._number(), patchSet, path));
+    anchor.setTitle("Edit");
+    return anchor;
+  }
+
   private Integer getSelectedPatchSet() {
     return sideA() ? basePatchSet : Integer.valueOf(patchSet);
   }
@@ -179,4 +203,15 @@
     return url.toString();
   }
 
+  private static String getEditUrl(int changeId, int patchSetId, String path) {
+    StringBuilder url = new StringBuilder();
+    url.append("/c/");
+    url.append(changeId);
+    url.append("/");
+    url.append(patchSetId);
+    url.append("/");
+    url.append(path);
+    url.append(",edit");
+    return url.toString();
+  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java
index 96555d3..0f6877f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/xdocs/client/XDocDiffScreen.java
@@ -60,6 +60,7 @@
             @Override
             public void onSuccess(EditInfo edit) {
               if (edit != null) {
+                change.set_edit(edit);
                 change.revisions().put(edit.name(), RevisionInfo.fromEdit(edit));
               }
               initRevisionsAndShow(change);