Partially implemented file upload. It only creates a 0 sized object
[pithos] / web_client / src / gr / grnet / pithos / web / client / FileUploadDialog.java
1 /*
2  * Copyright 2011 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35 package gr.grnet.pithos.web.client;
36
37 import com.google.gwt.core.client.Scheduler;
38 import com.google.gwt.http.client.Response;
39 import gr.grnet.pithos.web.client.foldertree.File;
40 import gr.grnet.pithos.web.client.foldertree.Folder;
41 import gr.grnet.pithos.web.client.foldertree.Resource;
42 import gr.grnet.pithos.web.client.rest.GetCommand;
43 import gr.grnet.pithos.web.client.rest.PostCommand;
44 import gr.grnet.pithos.web.client.rest.PutRequest;
45 import gr.grnet.pithos.web.client.rest.RestCommand;
46 import gr.grnet.pithos.web.client.rest.RestException;
47 import gr.grnet.pithos.web.client.rest.resource.FileResource;
48 import gr.grnet.pithos.web.client.rest.resource.FolderResource;
49 import gr.grnet.pithos.web.client.rest.resource.RestResourceWrapper;
50 import gr.grnet.pithos.web.client.rest.resource.UploadStatusResource;
51
52 import java.util.ArrayList;
53 import java.util.List;
54
55 import com.google.gwt.core.client.GWT;
56 import com.google.gwt.dom.client.NativeEvent;
57 import com.google.gwt.event.dom.client.ClickEvent;
58 import com.google.gwt.event.dom.client.ClickHandler;
59 import com.google.gwt.event.dom.client.KeyCodes;
60 import com.google.gwt.http.client.URL;
61 import com.google.gwt.json.client.JSONObject;
62 import com.google.gwt.json.client.JSONString;
63 import com.google.gwt.user.client.DeferredCommand;
64 import com.google.gwt.user.client.Event.NativePreviewEvent;
65 import com.google.gwt.user.client.Timer;
66 import com.google.gwt.user.client.ui.Button;
67 import com.google.gwt.user.client.ui.DialogBox;
68 import com.google.gwt.user.client.ui.FileUpload;
69 import com.google.gwt.user.client.ui.FormPanel;
70 import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
71 import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
72 import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
73 import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
74 import com.google.gwt.user.client.ui.Grid;
75 import com.google.gwt.user.client.ui.HTML;
76 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
77 import com.google.gwt.user.client.ui.Hidden;
78 import com.google.gwt.user.client.ui.HorizontalPanel;
79 import com.google.gwt.user.client.ui.Label;
80 import com.google.gwt.user.client.ui.VerticalPanel;
81 import javax.xml.transform.Templates;
82
83 /**
84  * The 'File upload' dialog box implementation.
85  */
86 public class FileUploadDialog extends DialogBox {
87
88     public static final boolean DONE = true;
89
90         /**
91          * The Form element that performs the file upload.
92          */
93         private final FormPanel form = new FormPanel();
94
95         private final FileUpload upload = new FileUpload();
96
97         private final Label filenameLabel = new Label();
98
99     private final Label foldernameLabel = new Label();
100
101     private Button submit;
102
103         protected Folder folder;
104
105     protected GSS app;
106
107         /**
108          * The widget's constructor.
109          */
110         public FileUploadDialog() {
111                 // Set the dialog's caption.
112                 setText("File upload");
113                 setAnimationEnabled(true);
114                 // Since we're going to add a FileUpload widget, we'll need to set the
115                 // form to use the POST method, and multipart MIME encoding.
116                 form.setEncoding(FormPanel.ENCODING_MULTIPART);
117                 form.setMethod(FormPanel.METHOD_POST);
118
119                 // Create a panel to hold all of the form widgets.
120                 VerticalPanel panel = new VerticalPanel();
121                 form.setWidget(panel);
122                 final HTML info = new HTML("You may select a file to upload. Install" +
123                                 " <a href='http://gears.google.com/' target='_blank'>Google " +
124                                 "Gears</a><br> for uploading multiple files simultaneously.");
125                 info.addStyleName("pithos-uploadNote");
126                 panel.add(info);
127
128         final Hidden auth = new Hidden("X-Auth-Token", "");
129         panel.add(auth);
130                 upload.setName("file");
131                 filenameLabel.setText("");
132                 filenameLabel.setVisible(false);
133                 filenameLabel.setStyleName("props-labels");
134                 HorizontalPanel fileUploadPanel = new HorizontalPanel();
135                 fileUploadPanel.add(filenameLabel);
136                 fileUploadPanel.add(upload);
137                 Grid generalTable = new Grid(2, 2);
138                 generalTable.setText(0, 0, "Folder");
139         generalTable.setWidget(0, 1, foldernameLabel);
140                 generalTable.setText(1, 0, "File");
141                 generalTable.setWidget(1, 1, fileUploadPanel);
142                 generalTable.getCellFormatter().setStyleName(0, 0, "props-labels");
143         generalTable.getCellFormatter().setStyleName(0, 1, "props-values");
144                 generalTable.getCellFormatter().setStyleName(1, 0, "props-labels");
145                 generalTable.getCellFormatter().setStyleName(1, 1, "props-values");
146                 generalTable.setCellSpacing(4);
147
148                 panel.add(generalTable);
149
150                 // Create a panel to hold the buttons.
151                 HorizontalPanel buttons = new HorizontalPanel();
152
153                 // Create the 'upload' button, along with a listener that submits the
154                 // form.
155                 submit = new Button("Upload", new ClickHandler() {
156                         @Override
157                         public void onClick(ClickEvent event) {
158                                 prepareAndSubmit();
159                         }
160                 });
161                 buttons.add(submit);
162                 buttons.setCellHorizontalAlignment(submit, HasHorizontalAlignment.ALIGN_CENTER);
163                 // Create the 'Cancel' button, along with a listener that hides the
164                 // dialog when the button is clicked.
165                 final Button cancel = new Button("Cancel", new ClickHandler() {
166                         @Override
167                         public void onClick(ClickEvent event) {
168                                 hide();
169                         }
170                 });
171                 buttons.add(cancel);
172                 buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
173                 buttons.setSpacing(8);
174                 buttons.addStyleName("pithos-DialogBox");
175         panel.add(buttons);
176         panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
177
178                 // Add an event handler to the form.
179                 form.addSubmitHandler(new SubmitHandler() {
180
181                         @Override
182                         public void onSubmit(SubmitEvent event) {
183                 auth.setValue(app.getToken()); //This is done here because the app object is not available in the constructor
184                         }
185                 });
186                 form.addSubmitCompleteHandler(new SubmitCompleteHandler() {
187
188                         @Override
189                         public void onSubmitComplete(SubmitCompleteEvent event) {
190                                 // When the form submission is successfully completed, this
191                                 // event is fired. Assuming the service returned a response
192                                 // of type text/html, we can get the result text here (see
193                                 // the FormPanel documentation for further explanation).
194                                 String results = event.getResults();
195
196                                 // Unfortunately the results are never empty, even in
197                                 // the absense of errors, so we have to check for '<pre></pre>'.
198                                 if (results != null && !results.equalsIgnoreCase("<pre></pre>")) {
199                                         GWT.log(results, null);
200                                         app.displayError(results);
201                                 }
202                 app.updateFolder(folder);
203                                 hide();
204                         }
205                 });
206
207
208                 panel.addStyleName("pithos-DialogBox");
209                 addStyleName("pithos-DialogBox");
210                 setWidget(form);
211         }
212
213         @Override
214         protected void onPreviewNativeEvent(NativePreviewEvent preview) {
215                 super.onPreviewNativeEvent(preview);
216
217                 NativeEvent evt = preview.getNativeEvent();
218                 if (evt.getType().equals("keydown"))
219                         // Use the popup's key preview hooks to close the dialog when either
220                         // enter or escape is pressed.
221                         switch (evt.getKeyCode()) {
222                                 case KeyCodes.KEY_ENTER:
223                                         prepareAndSubmit();
224                                         break;
225                                 case KeyCodes.KEY_ESCAPE:
226                                         hide();
227                                         break;
228                         }
229         }
230
231         /**
232          * Make any last minute checks and start the upload.
233          */
234         protected void prepareAndSubmit() {
235         if (upload.getFilename().length() == 0) {
236             app.displayError("You must select a file!");
237             return;
238         }
239         final String fname = getFilename(upload.getFilename());
240         String apath = app.getApiPath() + app.getUsername() + folder.getUri() + "/" + fname;
241         form.setAction(apath);
242         submit.setEnabled(false);
243         upload.setVisible(false);
244         filenameLabel.setText(fname);
245         filenameLabel.setVisible(true);
246
247                 if (getFileForName(fname) == null) {
248                         doUpload(apath);
249                 }
250                 else {
251                         // We are going to update an existing file, so show a confirmation dialog.
252                         ConfirmationDialog confirm = new ConfirmationDialog("Are you sure " +
253                                         "you want to update " + fname + "?", "Update") {
254
255                                 @Override
256                                 public void cancel() {
257                                         FileUploadDialog.this.hide();
258                                 }
259
260                                 @Override
261                                 public void confirm() {
262                                         form.submit();
263                                 }
264
265                         };
266                         confirm.center();
267                 }
268         }
269
270     private void doUpload(String path) {
271         PutRequest createFile = new PutRequest(path) {
272             @Override
273             public void onSuccess(Resource result) {
274                 form.submit();
275             }
276
277             @Override
278             public void onError(Throwable t) {
279                 GWT.log("", t);
280                 if (t instanceof RestException) {
281                     app.displayError("Unable to create file:" + ((RestException) t).getHttpStatusText());
282                 }
283                 else
284                     app.displayError("System error creating file:" + t.getMessage());
285             }
286         };
287         createFile.setHeader("X-Auth-Token", app.getToken());
288         createFile.setHeader("Content-Length", "0");
289         Scheduler.get().scheduleDeferred(createFile);
290     }
291
292     /**
293          * Returns the file name from a potential full path argument. Apparently IE
294          * insists on sending the full path name of a file when uploading, forcing
295          * us to trim the extra path info. Since this is only observed on Windows we
296          * get to check for a single path separator value.
297          *
298          * @param name the potentially full path name of a file
299          * @return the file name without extra path information
300          */
301         protected String getFilename(String name) {
302                 int pathSepIndex = name.lastIndexOf("\\");
303                 if (pathSepIndex == -1) {
304                         pathSepIndex = name.lastIndexOf("/");
305                         if (pathSepIndex == -1)
306                                 return name;
307                 }
308                 return name.substring(pathSepIndex + 1);
309         }
310
311         protected File getFileForName(String name){
312                 for (File f : folder.getFiles())
313                         if (!f.isInTrash() && f.getName().equals(name))
314                                 return f;
315                 return null;
316         }
317
318     public void setApp(GSS app) {
319         this.app = app;
320     }
321
322     public void setFolder(Folder folder) {
323         this.folder = folder;
324         foldernameLabel.setText(folder.getName());
325     }
326 }