Fixed folder deletion with all subfolders and files
[pithos] / web_client / src / gr / grnet / pithos / web / client / DeleteFolderDialog.java
1 /*\r
2  * Copyright 2011 GRNET S.A. All rights reserved.\r
3  *\r
4  * Redistribution and use in source and binary forms, with or\r
5  * without modification, are permitted provided that the following\r
6  * conditions are met:\r
7  *\r
8  *   1. Redistributions of source code must retain the above\r
9  *      copyright notice, this list of conditions and the following\r
10  *      disclaimer.\r
11  *\r
12  *   2. Redistributions in binary form must reproduce the above\r
13  *      copyright notice, this list of conditions and the following\r
14  *      disclaimer in the documentation and/or other materials\r
15  *      provided with the distribution.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
28  * POSSIBILITY OF SUCH DAMAGE.\r
29  *\r
30  * The views and conclusions contained in the software and\r
31  * documentation are those of the authors and should not be\r
32  * interpreted as representing official policies, either expressed\r
33  * or implied, of GRNET S.A.\r
34  */\r
35 package gr.grnet.pithos.web.client;\r
36 \r
37 import com.google.gwt.core.client.Scheduler;\r
38 import com.google.gwt.event.dom.client.KeyDownEvent;\r
39 import com.google.gwt.http.client.Request;\r
40 import com.google.gwt.http.client.RequestBuilder;\r
41 import com.google.gwt.http.client.RequestCallback;\r
42 import com.google.gwt.http.client.RequestException;\r
43 import com.google.gwt.http.client.Response;\r
44 import com.google.gwt.json.client.JSONArray;\r
45 import com.google.gwt.json.client.JSONObject;\r
46 import com.google.gwt.json.client.JSONParser;\r
47 import com.google.gwt.json.client.JSONString;\r
48 import com.google.gwt.json.client.JSONValue;\r
49 import com.google.gwt.user.client.Event;\r
50 import gr.grnet.pithos.web.client.MessagePanel.Images;\r
51 import gr.grnet.pithos.web.client.foldertree.File;\r
52 import gr.grnet.pithos.web.client.foldertree.Folder;\r
53 import gr.grnet.pithos.web.client.foldertree.Resource;\r
54 import gr.grnet.pithos.web.client.rest.DeleteCommand;\r
55 import gr.grnet.pithos.web.client.rest.DeleteRequest;\r
56 import gr.grnet.pithos.web.client.rest.GetRequest;\r
57 import gr.grnet.pithos.web.client.rest.RestException;\r
58 import gr.grnet.pithos.web.client.rest.RestRequestCallback;\r
59 import gr.grnet.pithos.web.client.rest.resource.FolderResource;\r
60 import gr.grnet.pithos.web.client.rest.resource.RestResource;\r
61 import gr.grnet.pithos.web.client.rest.resource.RestResourceWrapper;\r
62 import gr.grnet.pithos.web.client.rest.resource.TrashFolderResource;\r
63 \r
64 import com.google.gwt.core.client.GWT;\r
65 import com.google.gwt.dom.client.NativeEvent;\r
66 import com.google.gwt.event.dom.client.ClickEvent;\r
67 import com.google.gwt.event.dom.client.ClickHandler;\r
68 import com.google.gwt.event.dom.client.KeyCodes;\r
69 import com.google.gwt.user.client.DeferredCommand;\r
70 import com.google.gwt.user.client.Event.NativePreviewEvent;\r
71 import com.google.gwt.user.client.ui.AbstractImagePrototype;\r
72 import com.google.gwt.user.client.ui.Button;\r
73 import com.google.gwt.user.client.ui.DialogBox;\r
74 import com.google.gwt.user.client.ui.HTML;\r
75 import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
76 import com.google.gwt.user.client.ui.HorizontalPanel;\r
77 import com.google.gwt.user.client.ui.VerticalPanel;\r
78 import java.util.Iterator;\r
79 import java.util.List;\r
80 \r
81 /**\r
82  * The 'delete folder' dialog box.\r
83  */\r
84 public class DeleteFolderDialog extends DialogBox {\r
85 \r
86     private GSS app;\r
87     private Folder folder;\r
88     \r
89         /**\r
90          * The widget's constructor.\r
91          * @param images the supplied images\r
92          */\r
93         public DeleteFolderDialog(GSS app, Images images, Folder folder) {\r
94         this.app = app;\r
95         this.folder = folder;\r
96                 // Set the dialog's caption.\r
97                 setText("Confirmation");\r
98                 setAnimationEnabled(true);\r
99                 // Create a VerticalPanel to contain the HTML label and the buttons.\r
100                 VerticalPanel outer = new VerticalPanel();\r
101                 HorizontalPanel buttons = new HorizontalPanel();\r
102 \r
103                 HTML text = new HTML("<table><tr><td rowspan='2'>" + AbstractImagePrototype.create(images.warn()).getHTML() +\r
104                                         "</td><td>" + "Are you sure you want to <b>permanently</b> delete folder '" + folder.getName() +\r
105                                         "'?</td></tr></table>");\r
106                 text.setStyleName("pithos-warnMessage");\r
107                 outer.add(text);\r
108 \r
109                 // Create the 'Delete' button, along with a listener that hides the dialog\r
110                 // when the button is clicked and deletes the folder.\r
111                 Button ok = new Button("Delete", new ClickHandler() {\r
112                         @Override\r
113                         public void onClick(ClickEvent event) {\r
114                                 deleteFolder();\r
115                                 hide();\r
116                         }\r
117                 });\r
118                 buttons.add(ok);\r
119                 buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
120                 // Create the 'Cancel' button, along with a listener that hides the\r
121                 // dialog when the button is clicked.\r
122                 Button cancel = new Button("Cancel", new ClickHandler() {\r
123                         @Override\r
124                         public void onClick(ClickEvent event) {\r
125                                 hide();\r
126                         }\r
127                 });\r
128                 buttons.add(cancel);\r
129                 buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
130                 buttons.setSpacing(8);\r
131                 buttons.setStyleName("pithos-warnMessage");\r
132                 outer.setStyleName("pithos-warnMessage");\r
133                 outer.add(buttons);\r
134                 outer.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_CENTER);\r
135                 outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
136                 setWidget(outer);\r
137         }\r
138 \r
139         /**\r
140          * Generate an RPC request to delete a folder.\r
141          *\r
142          */\r
143         private void deleteFolder() {\r
144         String path = app.getApiPath() + app.getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + folder.getPrefix();\r
145         RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);\r
146         builder.setHeader("If-Modified-Since", "0");\r
147         builder.setHeader("X-Auth-Token", app.getToken());\r
148         try {\r
149             builder.sendRequest("", new RequestCallback() {\r
150                 @Override\r
151                 public void onResponseReceived(Request request, Response response) {\r
152                     if (response.getStatusCode() == Response.SC_OK) {\r
153                         JSONValue json = JSONParser.parseStrict(response.getText());\r
154                         JSONArray array = json.isArray();\r
155                         int i = 0;\r
156                         if (array != null) {\r
157                             deleteObject(i, array);\r
158                         }\r
159                     }\r
160                 }\r
161 \r
162                 @Override\r
163                 public void onError(Request request, Throwable exception) {\r
164                     GSS.get().displayError("System error unable to delete folder: " + exception.getMessage());\r
165                 }\r
166             });\r
167         }\r
168         catch (RequestException e) {\r
169         }\r
170         }\r
171 \r
172     private void deleteObject(final int i, final JSONArray array) {\r
173         if (i < array.size()) {\r
174             JSONObject o = array.get(i).isObject();\r
175             if (o != null && !o.containsKey("subdir")) {\r
176                 JSONString name = o.get("name").isString();\r
177                 String path = app.getApiPath() + app.getUsername() + "/" + folder.getContainer() + "/" + name.stringValue();\r
178                 DeleteRequest delete = new DeleteRequest(path) {\r
179                     @Override\r
180                     public void onSuccess(Resource result) {\r
181                         deleteObject(i + 1, array);\r
182                     }\r
183 \r
184                     @Override\r
185                     public void onError(Throwable t) {\r
186                         GWT.log("", t);\r
187                         GSS.get().displayError("System error unable to delete folder: " + t.getMessage());\r
188                     }\r
189                 };\r
190                 delete.setHeader("X-Auth-Token", app.getToken());\r
191                 Scheduler.get().scheduleDeferred(delete);\r
192             }\r
193             else {\r
194                 String subdir = o.get("subdir").isString().stringValue();\r
195                 subdir = subdir.substring(0, subdir.length() - 1);\r
196                 String path = app.getApiPath() + app.getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + subdir;\r
197                 RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);\r
198                 builder.setHeader("If-Modified-Since", "0");\r
199                 builder.setHeader("X-Auth-Token", app.getToken());\r
200                 try {\r
201                     builder.sendRequest("", new RequestCallback() {\r
202                         @Override\r
203                         public void onResponseReceived(Request request, Response response) {\r
204                             if (response.getStatusCode() == Response.SC_OK) {\r
205                                 JSONValue json = JSONParser.parseStrict(response.getText());\r
206                                 JSONArray array2 = json.isArray();\r
207                                 if (array2 != null) {\r
208                                     int l = array.size();\r
209                                     for (int j=0; j<array2.size(); j++) {\r
210                                         array.set(l++, array2.get(j));\r
211                                     }\r
212                                 }\r
213                                 deleteObject(i + 1, array);\r
214                             }\r
215                         }\r
216 \r
217                         @Override\r
218                         public void onError(Request request, Throwable exception) {\r
219                             GSS.get().displayError("System error unable to delete folder: " + exception.getMessage());\r
220                         }\r
221                     });\r
222                 }\r
223                 catch (RequestException e) {\r
224                 }\r
225             }\r
226         }\r
227         else {\r
228             String prefix = folder.getPrefix();\r
229             String path = app.getApiPath() + app.getUsername() + "/" + folder.getContainer() + (prefix.length() == 0 ? "" : "/" + prefix);\r
230             DeleteRequest deleteFolder = new DeleteRequest(path) {\r
231                 @Override\r
232                 public void onSuccess(Resource result) {\r
233                     app.updateFolder(folder.getParent());\r
234                 }\r
235 \r
236                 @Override\r
237                 public void onError(Throwable t) {\r
238                     GWT.log("", t);\r
239                     if (t instanceof RestException) {\r
240                         app.displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText());\r
241                     }\r
242                     else\r
243                         GSS.get().displayError("System error unable to delete folder: " + t.getMessage());\r
244                 }\r
245             };\r
246             deleteFolder.setHeader("X-Auth-Token", app.getToken());\r
247             Scheduler.get().scheduleDeferred(deleteFolder);\r
248         }\r
249     }\r
250 \r
251         @Override\r
252         protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
253                 super.onPreviewNativeEvent(preview);\r
254 \r
255                 NativeEvent evt = preview.getNativeEvent();\r
256                 if (evt.getType().equals(KeyDownEvent.getType().getName()))\r
257                         // Use the popup's key preview hooks to close the dialog when either\r
258                         // enter or escape is pressed.\r
259                         switch (evt.getKeyCode()) {\r
260                                 case KeyCodes.KEY_ENTER:\r
261                                         hide();\r
262                                         deleteFolder();\r
263                                         break;\r
264                                 case KeyCodes.KEY_ESCAPE:\r
265                                         hide();\r
266                                         break;\r
267                         }\r
268         }\r
269 \r
270 }\r