Allow deletion of just uploaded images from WebUI

Change-Id: I793eea5754dbe3ab99301ad9fde66ec590ff202f
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationCallback.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationCallback.java
new file mode 100644
index 0000000..05ae8f3
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationCallback.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2010 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.imagare.client;
+
+/**
+ * Interface that a caller must implement to react on the result of a
+ * {@link ConfirmationDialog}.
+ */
+public abstract class ConfirmationCallback {
+
+  /**
+   * Called when the {@link ConfirmationDialog} is finished with OK.
+   * To be overwritten by subclasses.
+   */
+  public abstract void onOk();
+
+  /**
+   * Called when the {@link ConfirmationDialog} is finished with Cancel.
+   * To be overwritten by subclasses.
+   */
+  public void onCancel() {
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationDialog.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationDialog.java
new file mode 100644
index 0000000..0b8dd70
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/ConfirmationDialog.java
@@ -0,0 +1,76 @@
+// Copyright (C) 2010 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.imagare.client;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.safehtml.client.SafeHtml;
+import com.google.gwtexpui.user.client.AutoCenterDialogBox;
+
+public class ConfirmationDialog extends AutoCenterDialogBox {
+
+  private Button cancelButton;
+
+  public ConfirmationDialog(final String dialogTitle, final SafeHtml message,
+      final ConfirmationCallback callback) {
+    super(/* auto hide */false, /* modal */true);
+    setGlassEnabled(true);
+    setText(dialogTitle);
+
+    final FlowPanel buttons = new FlowPanel();
+
+    final Button okButton = new Button();
+    okButton.setText("OK");
+    okButton.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        hide();
+        callback.onOk();
+      }
+    });
+    buttons.add(okButton);
+
+    cancelButton = new Button();
+    cancelButton.getElement().getStyle().setProperty("marginLeft", "300px");
+    cancelButton.setText("Cancel");
+    cancelButton.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        hide();
+        callback.onCancel();
+      }
+    });
+    buttons.add(cancelButton);
+
+    final FlowPanel center = new FlowPanel();
+    final Widget msgWidget = message.toBlockWidget();
+    center.add(msgWidget);
+    center.add(buttons);
+    add(center);
+
+    msgWidget.setWidth("400px");
+
+    setWidget(center);
+  }
+
+  @Override
+  public void center() {
+    super.center();
+    cancelButton.setFocus(true);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java
index 4e2f861..86884e3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/imagare/client/UploadedImagesPanel.java
@@ -14,6 +14,9 @@
 
 package com.googlesource.gerrit.plugins.imagare.client;
 
+import com.google.gerrit.plugin.client.Plugin;
+import com.google.gerrit.plugin.client.rpc.NoContent;
+import com.google.gerrit.plugin.client.rpc.RestApi;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.MouseOutEvent;
@@ -22,12 +25,14 @@
 import com.google.gwt.event.dom.client.MouseOverHandler;
 import com.google.gwt.user.client.Timer;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.PopupPanel;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwtexpui.clippy.client.CopyableLabel;
+import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
 public class UploadedImagesPanel extends FlowPanel {
 
@@ -55,12 +60,18 @@
     private final Image img;
     private final Image fullScreenIcon;
     private Timer fullScreenIconHideTimer;
+    private final Image deleteIcon;
+    private Timer deleteIconHideTimer;
 
     ImagePreview(final String url) {
       setStyleName("imagare-uploaded-image-preview-panel");
 
-      String fileName = url.substring(url.indexOf('/', url.indexOf("/rev/") + 5) + 1);
-      fileName = fileName.replaceAll("\\+", " ");
+      int revIndex = url.indexOf("/rev/");
+      int projectIndex = url.lastIndexOf('/', revIndex - 1);
+      int fileIndex = url.indexOf('/', revIndex + 5);
+      final String project = url.substring(projectIndex + 1, revIndex);
+      final String ref = url.substring(revIndex + 5, fileIndex);
+      final String fileName = url.substring(fileIndex + 1).replaceAll("\\+", " ");
       Label fileNameLabel = new Label(fileName);
       fileNameLabel.setStyleName("imagare-uploaded-image-title");
       add(fileNameLabel);
@@ -75,6 +86,12 @@
       fullScreenIcon.setVisible(false);
       add(fullScreenIcon);
 
+      deleteIcon = new Image(ImagarePlugin.RESOURCES.delete());
+      deleteIcon.setStyleName("imagare-delete-icon");
+      deleteIcon.setTitle("Delete Image");
+      deleteIcon.setVisible(false);
+      add(deleteIcon);
+
       img.addMouseOverHandler(new MouseOverHandler() {
         @Override
         public void onMouseOver(MouseOverEvent event) {
@@ -97,6 +114,13 @@
                   + "position: absolute; top: " + img.getAbsoluteTop() + "px; "
                   + "left: " + img.getAbsoluteLeft() + "px;");
           fullScreenIcon.setVisible(true);
+
+          cancelHideDeleteIcon();
+          deleteIcon.getElement().setAttribute("style",
+              deleteIcon.getElement().getAttribute("style")
+                  + "position: absolute; top: " + img.getAbsoluteTop() + "px; "
+                  + "left: " + (img.getAbsoluteLeft() + fullScreenIcon.getWidth()) + "px;");
+          deleteIcon.setVisible(true);
         }
       });
       img.addMouseOutHandler(new MouseOutHandler() {
@@ -105,6 +129,7 @@
           popup.setVisible(false);
           popup.clear();
           hideFullScreenIcon();
+          hideDeleteIcon();
         }
       });
 
@@ -112,6 +137,7 @@
         @Override
         public void onMouseOver(MouseOverEvent event) {
           cancelHideFullScreenIcon();
+          cancelHideDeleteIcon();
         }
       });
 
@@ -119,6 +145,7 @@
         @Override
         public void onMouseOut(MouseOutEvent event) {
           hideFullScreenIcon();
+          hideDeleteIcon();
         }
       });
 
@@ -131,6 +158,53 @@
         }
       });
 
+      deleteIcon.addMouseOverHandler(new MouseOverHandler() {
+        @Override
+        public void onMouseOver(MouseOverEvent event) {
+          cancelHideFullScreenIcon();
+          cancelHideDeleteIcon();
+        }
+      });
+
+      deleteIcon.addMouseOutHandler(new MouseOutHandler() {
+        @Override
+        public void onMouseOut(MouseOutEvent event) {
+          hideDeleteIcon();
+          hideFullScreenIcon();
+        }
+      });
+
+      deleteIcon.addClickHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          new ConfirmationDialog("Delete Image",
+              new SafeHtmlBuilder().append("Are you sure you want to delete '" + fileName + "'?").br().br(),
+              new ConfirmationCallback() {
+                @Override
+                public void onOk() {
+                  new RestApi("projects").view(project)
+                      .view(Plugin.get().getPluginName(), "images").view(ref)
+                      .delete(new AsyncCallback<NoContent>() {
+                        @Override
+                        public void onSuccess(NoContent info) {
+                          UploadedImagesPanel.this.remove(ImagePreview.this);
+                          uploadedImagesLabel.setVisible(
+                              UploadedImagesPanel.this.getWidgetCount() > 1);
+
+                          popup.setVisible(false);
+                          popup.clear();
+                        }
+
+                        @Override
+                        public void onFailure(Throwable caught) {
+                          // never invoked
+                        }
+                      });
+                }
+              }).center();
+        }
+      });
+
       CopyableLabel copyLabel = new CopyableLabel(url);
       copyLabel.setStyleName("imagare-uploaded-copy-label");
       add(copyLabel);
@@ -152,5 +226,22 @@
         fullScreenIconHideTimer = null;
       }
     }
+
+    private void hideDeleteIcon() {
+      deleteIconHideTimer = new Timer() {
+        @Override
+        public void run() {
+          deleteIcon.setVisible(false);
+        }
+      };
+      deleteIconHideTimer.schedule(20);
+    }
+
+    private void cancelHideDeleteIcon() {
+      if (deleteIconHideTimer != null) {
+        deleteIconHideTimer.cancel();
+        deleteIconHideTimer = null;
+      }
+    }
   }
 }