Revision 623:66f69a7348ed src/gr/ebs/gss/client/FileUploadGearsDialog.java

b/src/gr/ebs/gss/client/FileUploadGearsDialog.java
1
/*
2
 * Copyright 2009 Electronic Business Systems Ltd.
3
 *
4
 * This file is part of GSS.
5
 *
6
 * GSS is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * GSS is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
package gr.ebs.gss.client;
20

  
21
import gr.ebs.gss.client.rest.PostCommand;
22
import gr.ebs.gss.client.rest.RestCommand;
23
import gr.ebs.gss.client.rest.RestException;
24
import gr.ebs.gss.client.rest.resource.FileResource;
25
import gr.ebs.gss.client.rest.resource.FolderResource;
26

  
27
import java.util.ArrayList;
28
import java.util.Arrays;
29
import java.util.HashMap;
30
import java.util.List;
31
import java.util.Map;
32

  
33
import com.google.gwt.core.client.GWT;
34
import com.google.gwt.event.dom.client.ClickEvent;
35
import com.google.gwt.event.dom.client.ClickHandler;
36
import com.google.gwt.gears.client.Factory;
37
import com.google.gwt.gears.client.desktop.Desktop;
38
import com.google.gwt.gears.client.desktop.File;
39
import com.google.gwt.gears.client.desktop.OpenFilesHandler;
40
import com.google.gwt.gears.client.httprequest.HttpRequest;
41
import com.google.gwt.gears.client.httprequest.ProgressEvent;
42
import com.google.gwt.gears.client.httprequest.ProgressHandler;
43
import com.google.gwt.gears.client.httprequest.RequestCallback;
44
import com.google.gwt.http.client.URL;
45
import com.google.gwt.json.client.JSONObject;
46
import com.google.gwt.json.client.JSONString;
47
import com.google.gwt.user.client.Command;
48
import com.google.gwt.user.client.DeferredCommand;
49
import com.google.gwt.user.client.ui.Button;
50
import com.google.gwt.user.client.ui.FlexTable;
51
import com.google.gwt.user.client.ui.HTML;
52
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
53
import com.google.gwt.user.client.ui.HorizontalPanel;
54
import com.google.gwt.user.client.ui.VerticalPanel;
55

  
56
/**
57
 * The 'File upload' dialog box implementation with Google Gears support.
58
 */
59
public class FileUploadGearsDialog extends FileUploadDialog implements Updateable {
60

  
61
	protected final Factory factory = Factory.getInstance();
62

  
63
	/**
64
	 * The array of files to upload.
65
	 */
66
	private File[] fileObjects;
67

  
68
	/**
69
	 * A list of files to upload, created from files array. Used to signal
70
	 * finished state when empty.
71
	 */
72
	protected List<File> selectedFiles = new ArrayList<File>();
73

  
74
	/**
75
	 * The list of progress bars for individual files.
76
	 */
77
	protected List<ProgressBar> progressBars = new ArrayList<ProgressBar>();
78

  
79
	private Button browse;
80

  
81
	private Button submit;
82

  
83
	private FlexTable generalTable;
84

  
85
	private Map<String, FileResource> toRename;
86

  
87
	protected List<HttpRequest> requests = new ArrayList<HttpRequest>();
88

  
89
	/**
90
	 * The widget's constructor.
91
	 */
92
	public FileUploadGearsDialog() {
93
		// Set the dialog's caption.
94
		setText("File upload");
95
		setAnimationEnabled(true);
96
		// Create a panel to hold all of the dialog widgets.
97
		VerticalPanel panel = new VerticalPanel();
98
		final HTML info = new HTML("You may select one or more files to upload.");
99
		info.addStyleName("gss-uploadNote");
100
		panel.add(info);
101
		// Add an informative label with the folder name.
102
		Object selection = GSS.get().getFolders().getCurrent().getUserObject();
103
		folder = (FolderResource) selection;
104

  
105
		browse = new Button("Browse...");
106

  
107
		HorizontalPanel fileUploadPanel = new HorizontalPanel();
108
		fileUploadPanel.add(browse);
109

  
110
		generalTable = new FlexTable();
111
		generalTable.setText(0, 0, "Folder");
112
		generalTable.setText(1, 0, "File");
113
		generalTable.setText(0, 1, folder.getName());
114
		generalTable.setWidget(1, 1, fileUploadPanel);
115
		generalTable.getCellFormatter().setStyleName(0, 0, "props-labels");
116
		generalTable.getCellFormatter().setStyleName(1, 0, "props-labels");
117
		generalTable.getCellFormatter().setStyleName(0, 1, "props-values");
118
		generalTable.getCellFormatter().setStyleName(1, 1, "props-values");
119
		generalTable.setCellSpacing(4);
120

  
121
		panel.add(generalTable);
122

  
123
		// Create a panel to hold the buttons.
124
		HorizontalPanel buttons = new HorizontalPanel();
125

  
126
		submit = new Button("Upload");
127
		submit.addClickHandler(new ClickHandler() {
128
			@Override
129
			public void onClick(ClickEvent event) {
130
				prepareAndSubmit();
131
			}
132
		});
133
		submit.setEnabled(false);
134
		buttons.add(submit);
135
		buttons.setCellHorizontalAlignment(submit, HasHorizontalAlignment.ALIGN_CENTER);
136
		// Create the 'Cancel' button, along with a listener that hides the
137
		// dialog when the button is clicked.
138
		Button cancel = new Button("Cancel", new ClickHandler() {
139
			@Override
140
			public void onClick(ClickEvent event) {
141
				cancelUpload();
142
			}
143
		});
144
		buttons.add(cancel);
145
		buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
146
		buttons.setSpacing(8);
147
		buttons.addStyleName("gss-DialogBox");
148

  
149
		browse.addClickHandler(new ClickHandler() {
150
			@Override
151
			public void onClick(ClickEvent event) {
152
				Desktop desktop = factory.createDesktop();
153
				desktop.openFiles(new OpenFilesHandler() {
154

  
155
					public void onOpenFiles(OpenFilesEvent ofevent) {
156
						fileObjects = ofevent.getFiles();
157
						selectedFiles.addAll(Arrays.asList(fileObjects));
158
						for (int i = 0; i< selectedFiles.size(); i++) {
159
							generalTable.setText(i+1, 0, "File");
160
							generalTable.setText(i+1, 1, selectedFiles.get(i).getName());
161
							ProgressBar progress = new ProgressBar(20, 0);
162
							generalTable.setWidget(i+1, 2, progress);
163
							progressBars.add(progress);
164
							generalTable.getCellFormatter().setStyleName(i+1, 0, "props-labels");
165
							generalTable.getCellFormatter().setStyleName(i+1, 1, "props-values");
166
						}
167
						submit.setEnabled(true);
168
					}
169
				});
170
			}
171
		});
172

  
173
		panel.add(buttons);
174
		panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
175
		panel.addStyleName("gss-DialogBox");
176
		addStyleName("gss-DialogBox");
177
		setWidget(panel);
178
	}
179

  
180
	/**
181
	 * Cancels the file upload.
182
	 */
183
	private void cancelUpload() {
184
		for (HttpRequest request: requests)
185
			request.abort();
186
		hide();
187
	}
188

  
189
	/**
190
	 * Check whether the specified file name exists in the selected folder.
191
	 */
192
	private boolean canContinue(File file) {
193
		String fileName = getFilename(file.getName());
194
		if (getFileForName(fileName) == null)
195
			// For file creation, check to see if the file already exists.
196
			for (FileResource fileRes : files)
197
				if (!fileRes.isDeleted() && fileRes.getName().equals(fileName))
198
					return false;
199
		return true;
200
	}
201

  
202
	@Override
203
	public void prepareAndSubmit() {
204
		GSS app = GSS.get();
205
		if (selectedFiles.size() == 0) {
206
			app.displayError("You must select a file!");
207
			hide();
208
			return;
209
		}
210
		for (File file: selectedFiles)
211
			if (!canContinue(file)) {
212
				app.displayError("The file name " + file.getName() +
213
							" already exists in this folder");
214
				hide();
215
				return;
216
			}
217
		submit.setEnabled(false);
218
		browse.setVisible(false);
219
		List<String> toUpdate = new ArrayList<String>();
220
		toRename = new HashMap<String, FileResource>();
221
		for (File file: selectedFiles) {
222
			String fname = getFilename(file.getName());
223
			if (getFileForName(fname) == null) {
224
				// We are going to create a file, so we check to see if there is a
225
				// trashed file with the same name.
226
				FileResource same = null;
227
				for (FileResource fres : folder.getFiles())
228
					if (fres.isDeleted() && fres.getName().equals(fname))
229
						same = fres;
230
				// In that case add it to the list of files to rename.
231
				if (same != null)
232
					toRename.put(getBackupFilename(fname), same);
233
			} else
234
				// If we are updating a file add it to the list of files to update.
235
				toUpdate.add(fname);
236
		}
237

  
238
		if (!toUpdate.isEmpty()) {
239
			StringBuffer sb = new StringBuffer();
240
			for (String name: toUpdate)
241
				sb.append(name).append("<br/>");
242
			// We are going to update existing files, so show a confirmation dialog.
243
			ConfirmationDialog confirm = new ConfirmationDialog("Are you sure " +
244
					"you want to update the following files?<br/><i>" + sb +
245
					"</i>", "Update") {
246

  
247
				@Override
248
				public void cancel() {
249
					hide();
250
				}
251

  
252
				@Override
253
				public void confirm() {
254
					confirmRename();
255
				}
256

  
257
			};
258
			confirm.center();
259
		} else
260
			confirmRename();
261
	}
262

  
263
	/**
264
	 * Confirm the renames of synonymous files already in the trash.
265
	 */
266
	private void confirmRename() {
267
		if (!toRename.isEmpty()) {
268
			StringBuffer sb = new StringBuffer();
269
			for (FileResource file: toRename.values())
270
				sb.append(file.getName()).append("<br/>");
271
			ConfirmationDialog confirm = new ConfirmationDialog("Files " +
272
					"with the following names already exist in the trash. If" +
273
					" you continue,<br/>the trashed files will be renamed " +
274
					"automatically for you:<br/><i>" + sb + "</i>", "Continue") {
275

  
276
				@Override
277
				public void cancel() {
278
					hide();
279
				}
280

  
281
				@Override
282
				public void confirm() {
283
					updateTrashedFiles();
284
				}
285

  
286
			};
287
			confirm.center();
288
		} else
289
			uploadFiles();
290
	}
291

  
292
	/**
293
	 * Rename the conflicting trashed files with the supplied new names.
294
	 */
295
	private void updateTrashedFiles() {
296
		for (final String name: toRename.keySet()) {
297
			JSONObject json = new JSONObject();
298
			json.put("name", new JSONString(name));
299
			PostCommand cf = new PostCommand(toRename.get(name).getUri() + "?update=", json.toString(), 200) {
300

  
301
				@Override
302
				public void onComplete() {
303
					toRename.remove(name);
304
					uploadFiles();
305
				}
306

  
307
				@Override
308
				public void onError(Throwable t) {
309
					GSS app = GSS.get();
310
					GWT.log("", t);
311
					if (t instanceof RestException) {
312
						int statusCode = ((RestException) t).getHttpStatusCode();
313
						if (statusCode == 405)
314
							app.displayError("You don't have the necessary permissions");
315
						else if (statusCode == 404)
316
							app.displayError("User in permissions does not exist");
317
						else if (statusCode == 409)
318
							app.displayError("A file with the same name already exists");
319
						else if (statusCode == 413)
320
							app.displayError("Your quota has been exceeded");
321
						else
322
							app.displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());
323
					} else
324
						app.displayError("System error modifying file:" + t.getMessage());
325
				}
326

  
327
			};
328
			DeferredCommand.addCommand(cf);
329
		}
330
	}
331

  
332
	/**
333
	 * Checks if the renaming step for already trashed files is complete and
334
	 * starts file uploads.
335
	 */
336
	private void uploadFiles() {
337
		if (!toRename.isEmpty()) return;
338
		for (int i = 0; i< fileObjects.length; i++) {
339
			final int index = i;
340
			DeferredCommand.addCommand(new Command() {
341
				public void execute() {
342
					doSend(fileObjects[index], index);
343
				}
344
			});
345
		}
346
	}
347

  
348
	/**
349
	 * Perform the HTTP request to upload the specified file.
350
	 */
351
	protected void doSend(final File file, final int index) {
352
		final GSS app = GSS.get();
353
		HttpRequest request = factory.createHttpRequest();
354
		requests.add(request);
355
		String method = "PUT";
356

  
357
		String path;
358
		final String filename = getFilename(file.getName());
359
		path = folder.getUri();
360
		if (!path.endsWith("/"))
361
			path = path + "/";
362
		path = path + encode(filename);
363

  
364
		String token = app.getToken();
365
		String resource = path.substring(app.getApiPath().length()-1, path.length());
366
		String date = RestCommand.getDate();
367
		String sig = RestCommand.calculateSig(method, date, resource, RestCommand.base64decode(token));
368
		request.open(method, path);
369
		request.setRequestHeader("X-GSS-Date", date);
370
		request.setRequestHeader("Authorization", app.getCurrentUserResource().getUsername() + " " + sig);
371
		request.setRequestHeader("Accept", "application/json; charset=utf-8");
372
		request.setCallback(new RequestCallback() {
373
			public void onResponseReceived(HttpRequest req) {
374
				int state = req.getReadyState();
375
				if (state != 4) return;
376
				switch(req.getStatus()) {
377
					case 201: // Created falls through to updated.
378
					case 204:
379
						selectedFiles.remove(file);
380
						finish();
381
						break;
382
					case 403:
383
						SessionExpiredDialog dlg = new SessionExpiredDialog();
384
						dlg.center();
385
						break;
386
					case 405:
387
						app.displayError("You don't have permission to " +
388
								"upload file " + filename);
389
						break;
390
					case 409:
391
						app.displayError("A folder with the name " + filename +
392
								" already exists at this level");
393
						break;
394
					case 413:
395
						app.displayError("There is not enough free space " +
396
								"available for uploading " + filename);
397
						break;
398
					default:
399
						app.displayError("Error uploading file " + filename +
400
									": " + req.getStatus());
401
				}
402
			}
403
		});
404
		request.getUpload().setProgressHandler(new ProgressHandler() {
405
			public void onProgress(ProgressEvent event) {
406
				double pcnt = (double) event.getLoaded() / event.getTotal();
407
				progressBars.get(index).setProgress((int) Math.floor(pcnt * 100));
408
			}
409
		});
410
		request.send(file.getBlob());
411
	}
412

  
413
	/**
414
	 * Perform the final actions after the files are uploaded.
415
	 */
416
	protected void finish() {
417
		if (!selectedFiles.isEmpty()) return;
418
		hide();
419
		GSS.get().showFileList(true);
420
		GSS.get().getStatusPanel().updateStats();
421
	}
422

  
423
	/**
424
	 * Same as URL.encode, but also encode apostrophe since browsers aren't
425
	 * consistent about it (FF encodes, IE does not).
426
	 */
427
	protected String encode(String decodedURL) {
428
		String retv = decodedURL.replaceAll("@", "_"); // Replace bad character
429
		retv = URL.encodeComponent(retv);
430
		retv = retv.replaceAll("'", "%27");
431
		return retv;
432
	}
433

  
434
}
1
/*
2
 * Copyright 2009 Electronic Business Systems Ltd.
3
 *
4
 * This file is part of GSS.
5
 *
6
 * GSS is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * GSS is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
package gr.ebs.gss.client;
20

  
21
import gr.ebs.gss.client.rest.PostCommand;
22
import gr.ebs.gss.client.rest.RestCommand;
23
import gr.ebs.gss.client.rest.RestException;
24
import gr.ebs.gss.client.rest.resource.FileResource;
25
import gr.ebs.gss.client.rest.resource.FolderResource;
26

  
27
import java.util.ArrayList;
28
import java.util.Arrays;
29
import java.util.HashMap;
30
import java.util.List;
31
import java.util.Map;
32

  
33
import com.google.gwt.core.client.GWT;
34
import com.google.gwt.event.dom.client.ClickEvent;
35
import com.google.gwt.event.dom.client.ClickHandler;
36
import com.google.gwt.gears.client.Factory;
37
import com.google.gwt.gears.client.desktop.Desktop;
38
import com.google.gwt.gears.client.desktop.File;
39
import com.google.gwt.gears.client.desktop.OpenFilesHandler;
40
import com.google.gwt.gears.client.httprequest.HttpRequest;
41
import com.google.gwt.gears.client.httprequest.ProgressEvent;
42
import com.google.gwt.gears.client.httprequest.ProgressHandler;
43
import com.google.gwt.gears.client.httprequest.RequestCallback;
44
import com.google.gwt.http.client.URL;
45
import com.google.gwt.json.client.JSONObject;
46
import com.google.gwt.json.client.JSONString;
47
import com.google.gwt.user.client.Command;
48
import com.google.gwt.user.client.DeferredCommand;
49
import com.google.gwt.user.client.ui.Button;
50
import com.google.gwt.user.client.ui.FlexTable;
51
import com.google.gwt.user.client.ui.HTML;
52
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
53
import com.google.gwt.user.client.ui.HorizontalPanel;
54
import com.google.gwt.user.client.ui.VerticalPanel;
55

  
56
/**
57
 * The 'File upload' dialog box implementation with Google Gears support.
58
 */
59
public class FileUploadGearsDialog extends FileUploadDialog implements Updateable {
60

  
61
	protected final Factory factory = Factory.getInstance();
62

  
63
	/**
64
	 * The array of files to upload.
65
	 */
66
	private File[] fileObjects;
67

  
68
	/**
69
	 * A list of files to upload, created from files array. Used to signal
70
	 * finished state when empty.
71
	 */
72
	protected List<File> selectedFiles = new ArrayList<File>();
73

  
74
	/**
75
	 * The list of progress bars for individual files.
76
	 */
77
	protected List<ProgressBar> progressBars = new ArrayList<ProgressBar>();
78

  
79
	private Button browse;
80

  
81
	private Button submit;
82

  
83
	private FlexTable generalTable;
84

  
85
	private Map<String, FileResource> toRename;
86

  
87
	protected List<HttpRequest> requests = new ArrayList<HttpRequest>();
88

  
89
	/**
90
	 * The widget's constructor.
91
	 */
92
	public FileUploadGearsDialog() {
93
		// Set the dialog's caption.
94
		setText("File upload");
95
		setAnimationEnabled(true);
96
		// Create a panel to hold all of the dialog widgets.
97
		VerticalPanel panel = new VerticalPanel();
98
		final HTML info = new HTML("You may select one or more files to upload.");
99
		info.addStyleName("gss-uploadNote");
100
		panel.add(info);
101
		// Add an informative label with the folder name.
102
		Object selection = GSS.get().getFolders().getCurrent().getUserObject();
103
		folder = (FolderResource) selection;
104

  
105
		browse = new Button("Browse...");
106

  
107
		HorizontalPanel fileUploadPanel = new HorizontalPanel();
108
		fileUploadPanel.add(browse);
109

  
110
		generalTable = new FlexTable();
111
		generalTable.setText(0, 0, "Folder");
112
		generalTable.setText(1, 0, "File");
113
		generalTable.setText(0, 1, folder.getName());
114
		generalTable.setWidget(1, 1, fileUploadPanel);
115
		generalTable.getCellFormatter().setStyleName(0, 0, "props-labels");
116
		generalTable.getCellFormatter().setStyleName(1, 0, "props-labels");
117
		generalTable.getCellFormatter().setStyleName(0, 1, "props-values");
118
		generalTable.getCellFormatter().setStyleName(1, 1, "props-values");
119
		generalTable.setCellSpacing(4);
120

  
121
		panel.add(generalTable);
122

  
123
		// Create a panel to hold the buttons.
124
		HorizontalPanel buttons = new HorizontalPanel();
125

  
126
		submit = new Button("Upload");
127
		submit.addClickHandler(new ClickHandler() {
128
			@Override
129
			public void onClick(ClickEvent event) {
130
				prepareAndSubmit();
131
			}
132
		});
133
		submit.setEnabled(false);
134
		buttons.add(submit);
135
		buttons.setCellHorizontalAlignment(submit, HasHorizontalAlignment.ALIGN_CENTER);
136
		// Create the 'Cancel' button, along with a listener that hides the
137
		// dialog when the button is clicked.
138
		Button cancel = new Button("Cancel", new ClickHandler() {
139
			@Override
140
			public void onClick(ClickEvent event) {
141
				cancelUpload();
142
			}
143
		});
144
		buttons.add(cancel);
145
		buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
146
		buttons.setSpacing(8);
147
		buttons.addStyleName("gss-DialogBox");
148

  
149
		browse.addClickHandler(new ClickHandler() {
150
			@Override
151
			public void onClick(ClickEvent event) {
152
				Desktop desktop = factory.createDesktop();
153
				desktop.openFiles(new OpenFilesHandler() {
154

  
155
					@Override
156
					public void onOpenFiles(OpenFilesEvent ofevent) {
157
						fileObjects = ofevent.getFiles();
158
						selectedFiles.addAll(Arrays.asList(fileObjects));
159
						for (int i = 0; i< selectedFiles.size(); i++) {
160
							generalTable.setText(i+1, 0, "File");
161
							generalTable.setText(i+1, 1, selectedFiles.get(i).getName());
162
							ProgressBar progress = new ProgressBar(20, 0);
163
							generalTable.setWidget(i+1, 2, progress);
164
							progressBars.add(progress);
165
							generalTable.getCellFormatter().setStyleName(i+1, 0, "props-labels");
166
							generalTable.getCellFormatter().setStyleName(i+1, 1, "props-values");
167
						}
168
						submit.setEnabled(true);
169
					}
170
				});
171
			}
172
		});
173

  
174
		panel.add(buttons);
175
		panel.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
176
		panel.addStyleName("gss-DialogBox");
177
		addStyleName("gss-DialogBox");
178
		setWidget(panel);
179
	}
180

  
181
	/**
182
	 * Cancels the file upload.
183
	 */
184
	private void cancelUpload() {
185
		for (HttpRequest request: requests)
186
			request.abort();
187
		hide();
188
	}
189

  
190
	/**
191
	 * Check whether the specified file name exists in the selected folder.
192
	 */
193
	private boolean canContinue(File file) {
194
		String fileName = getFilename(file.getName());
195
		if (getFileForName(fileName) == null)
196
			// For file creation, check to see if the file already exists.
197
			for (FileResource fileRes : files)
198
				if (!fileRes.isDeleted() && fileRes.getName().equals(fileName))
199
					return false;
200
		return true;
201
	}
202

  
203
	@Override
204
	public void prepareAndSubmit() {
205
		GSS app = GSS.get();
206
		if (selectedFiles.size() == 0) {
207
			app.displayError("You must select a file!");
208
			hide();
209
			return;
210
		}
211
		for (File file: selectedFiles)
212
			if (!canContinue(file)) {
213
				app.displayError("The file name " + file.getName() +
214
							" already exists in this folder");
215
				hide();
216
				return;
217
			}
218
		submit.setEnabled(false);
219
		browse.setVisible(false);
220
		List<String> toUpdate = new ArrayList<String>();
221
		toRename = new HashMap<String, FileResource>();
222
		for (File file: selectedFiles) {
223
			String fname = getFilename(file.getName());
224
			if (getFileForName(fname) == null) {
225
				// We are going to create a file, so we check to see if there is a
226
				// trashed file with the same name.
227
				FileResource same = null;
228
				for (FileResource fres : folder.getFiles())
229
					if (fres.isDeleted() && fres.getName().equals(fname))
230
						same = fres;
231
				// In that case add it to the list of files to rename.
232
				if (same != null)
233
					toRename.put(getBackupFilename(fname), same);
234
			} else
235
				// If we are updating a file add it to the list of files to update.
236
				toUpdate.add(fname);
237
		}
238

  
239
		if (!toUpdate.isEmpty()) {
240
			StringBuffer sb = new StringBuffer();
241
			for (String name: toUpdate)
242
				sb.append(name).append("<br/>");
243
			// We are going to update existing files, so show a confirmation dialog.
244
			ConfirmationDialog confirm = new ConfirmationDialog("Are you sure " +
245
					"you want to update the following files?<br/><i>" + sb +
246
					"</i>", "Update") {
247

  
248
				@Override
249
				public void cancel() {
250
					hide();
251
				}
252

  
253
				@Override
254
				public void confirm() {
255
					confirmRename();
256
				}
257

  
258
			};
259
			confirm.center();
260
		} else
261
			confirmRename();
262
	}
263

  
264
	/**
265
	 * Confirm the renames of synonymous files already in the trash.
266
	 */
267
	private void confirmRename() {
268
		if (!toRename.isEmpty()) {
269
			StringBuffer sb = new StringBuffer();
270
			for (FileResource file: toRename.values())
271
				sb.append(file.getName()).append("<br/>");
272
			ConfirmationDialog confirm = new ConfirmationDialog("Files " +
273
					"with the following names already exist in the trash. If" +
274
					" you continue,<br/>the trashed files will be renamed " +
275
					"automatically for you:<br/><i>" + sb + "</i>", "Continue") {
276

  
277
				@Override
278
				public void cancel() {
279
					hide();
280
				}
281

  
282
				@Override
283
				public void confirm() {
284
					updateTrashedFiles();
285
				}
286

  
287
			};
288
			confirm.center();
289
		} else
290
			uploadFiles();
291
	}
292

  
293
	/**
294
	 * Rename the conflicting trashed files with the supplied new names.
295
	 */
296
	private void updateTrashedFiles() {
297
		for (final String name: toRename.keySet()) {
298
			JSONObject json = new JSONObject();
299
			json.put("name", new JSONString(name));
300
			PostCommand cf = new PostCommand(toRename.get(name).getUri() + "?update=", json.toString(), 200) {
301

  
302
				@Override
303
				public void onComplete() {
304
					toRename.remove(name);
305
					uploadFiles();
306
				}
307

  
308
				@Override
309
				public void onError(Throwable t) {
310
					GSS app = GSS.get();
311
					GWT.log("", t);
312
					if (t instanceof RestException) {
313
						int statusCode = ((RestException) t).getHttpStatusCode();
314
						if (statusCode == 405)
315
							app.displayError("You don't have the necessary permissions");
316
						else if (statusCode == 404)
317
							app.displayError("User in permissions does not exist");
318
						else if (statusCode == 409)
319
							app.displayError("A file with the same name already exists");
320
						else if (statusCode == 413)
321
							app.displayError("Your quota has been exceeded");
322
						else
323
							app.displayError("Unable to modify file:" + ((RestException) t).getHttpStatusText());
324
					} else
325
						app.displayError("System error modifying file:" + t.getMessage());
326
				}
327

  
328
			};
329
			DeferredCommand.addCommand(cf);
330
		}
331
	}
332

  
333
	/**
334
	 * Checks if the renaming step for already trashed files is complete and
335
	 * starts file uploads.
336
	 */
337
	private void uploadFiles() {
338
		if (!toRename.isEmpty()) return;
339
		for (int i = 0; i< fileObjects.length; i++) {
340
			final int index = i;
341
			DeferredCommand.addCommand(new Command() {
342
				@Override
343
				public void execute() {
344
					doSend(fileObjects[index], index);
345
				}
346
			});
347
		}
348
	}
349

  
350
	/**
351
	 * Perform the HTTP request to upload the specified file.
352
	 */
353
	protected void doSend(final File file, final int index) {
354
		final GSS app = GSS.get();
355
		HttpRequest request = factory.createHttpRequest();
356
		requests.add(request);
357
		String method = "PUT";
358

  
359
		String path;
360
		final String filename = getFilename(file.getName());
361
		path = folder.getUri();
362
		if (!path.endsWith("/"))
363
			path = path + "/";
364
		path = path + encode(filename);
365

  
366
		String token = app.getToken();
367
		String resource = path.substring(app.getApiPath().length()-1, path.length());
368
		String date = RestCommand.getDate();
369
		String sig = RestCommand.calculateSig(method, date, resource, RestCommand.base64decode(token));
370
		request.open(method, path);
371
		request.setRequestHeader("X-GSS-Date", date);
372
		request.setRequestHeader("Authorization", app.getCurrentUserResource().getUsername() + " " + sig);
373
		request.setRequestHeader("Accept", "application/json; charset=utf-8");
374
		request.setCallback(new RequestCallback() {
375
			@Override
376
			public void onResponseReceived(HttpRequest req) {
377
				int state = req.getReadyState();
378
				if (state != 4) return;
379
				switch(req.getStatus()) {
380
					case 201: // Created falls through to updated.
381
					case 204:
382
						selectedFiles.remove(file);
383
						finish();
384
						break;
385
					case 403:
386
						SessionExpiredDialog dlg = new SessionExpiredDialog();
387
						dlg.center();
388
						break;
389
					case 405:
390
						app.displayError("You don't have permission to " +
391
								"upload file " + filename);
392
						break;
393
					case 409:
394
						app.displayError("A folder with the name " + filename +
395
								" already exists at this level");
396
						break;
397
					case 413:
398
						app.displayError("There is not enough free space " +
399
								"available for uploading " + filename);
400
						break;
401
					default:
402
						app.displayError("Error uploading file " + filename +
403
									": " + req.getStatus());
404
				}
405
			}
406
		});
407
		request.getUpload().setProgressHandler(new ProgressHandler() {
408
			@Override
409
			public void onProgress(ProgressEvent event) {
410
				double pcnt = (double) event.getLoaded() / event.getTotal();
411
				progressBars.get(index).setProgress((int) Math.floor(pcnt * 100));
412
			}
413
		});
414
		request.send(file.getBlob());
415
	}
416

  
417
	/**
418
	 * Perform the final actions after the files are uploaded.
419
	 */
420
	protected void finish() {
421
		if (!selectedFiles.isEmpty()) return;
422
		hide();
423
		GSS.get().showFileList(true);
424
		GSS.get().getStatusPanel().updateStats();
425
	}
426

  
427
	/**
428
	 * Same as URL.encode, but also encode apostrophe since browsers aren't
429
	 * consistent about it (FF encodes, IE does not).
430
	 */
431
	protected String encode(String decodedURL) {
432
		String retv = decodedURL.replaceAll("@", "_"); // Replace bad character
433
		retv = URL.encodeComponent(retv);
434
		retv = retv.replaceAll("'", "%27");
435
		return retv;
436
	}
437

  
438
}

Also available in: Unified diff