First version of drag 'n' drop upload (issue #2224)
[pithos-web-client] / src / gr / grnet / pithos / web / client / Pithos.java
1 /*
2  * Copyright 2011-2012 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 gr.grnet.pithos.web.client.commands.UploadFileCommand;
38 import gr.grnet.pithos.web.client.foldertree.AccountResource;
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.FolderTreeView;
42 import gr.grnet.pithos.web.client.foldertree.FolderTreeViewModel;
43 import gr.grnet.pithos.web.client.foldertree.Resource;
44 import gr.grnet.pithos.web.client.grouptree.Group;
45 import gr.grnet.pithos.web.client.grouptree.GroupTreeView;
46 import gr.grnet.pithos.web.client.grouptree.GroupTreeViewModel;
47 import gr.grnet.pithos.web.client.mysharedtree.MysharedTreeView;
48 import gr.grnet.pithos.web.client.mysharedtree.MysharedTreeViewModel;
49 import gr.grnet.pithos.web.client.othersharedtree.OtherSharedTreeView;
50 import gr.grnet.pithos.web.client.othersharedtree.OtherSharedTreeViewModel;
51 import gr.grnet.pithos.web.client.rest.DeleteRequest;
52 import gr.grnet.pithos.web.client.rest.GetRequest;
53 import gr.grnet.pithos.web.client.rest.HeadRequest;
54 import gr.grnet.pithos.web.client.rest.PutRequest;
55 import gr.grnet.pithos.web.client.rest.RestException;
56
57 import java.util.ArrayList;
58 import java.util.HashMap;
59 import java.util.Iterator;
60 import java.util.List;
61 import java.util.Set;
62
63 import com.google.gwt.core.client.EntryPoint;
64 import com.google.gwt.core.client.GWT;
65 import com.google.gwt.core.client.Scheduler;
66 import com.google.gwt.core.client.Scheduler.RepeatingCommand;
67 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
68 import com.google.gwt.event.dom.client.ClickEvent;
69 import com.google.gwt.event.dom.client.ClickHandler;
70 import com.google.gwt.event.logical.shared.ResizeEvent;
71 import com.google.gwt.event.logical.shared.ResizeHandler;
72 import com.google.gwt.http.client.Request;
73 import com.google.gwt.http.client.RequestBuilder;
74 import com.google.gwt.http.client.RequestCallback;
75 import com.google.gwt.http.client.RequestException;
76 import com.google.gwt.http.client.Response;
77 import com.google.gwt.http.client.URL;
78 import com.google.gwt.i18n.client.Dictionary;
79 import com.google.gwt.i18n.client.NumberFormat;
80 import com.google.gwt.json.client.JSONArray;
81 import com.google.gwt.json.client.JSONObject;
82 import com.google.gwt.json.client.JSONParser;
83 import com.google.gwt.json.client.JSONString;
84 import com.google.gwt.json.client.JSONValue;
85 import com.google.gwt.resources.client.ImageResource;
86 import com.google.gwt.resources.client.ImageResource.ImageOptions;
87 import com.google.gwt.user.client.Command;
88 import com.google.gwt.user.client.Cookies;
89 import com.google.gwt.user.client.Event;
90 import com.google.gwt.user.client.History;
91 import com.google.gwt.user.client.Window;
92 import com.google.gwt.user.client.ui.AbstractImagePrototype;
93 import com.google.gwt.user.client.ui.Button;
94 import com.google.gwt.user.client.ui.Composite;
95 import com.google.gwt.user.client.ui.FlowPanel;
96 import com.google.gwt.user.client.ui.HTML;
97 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
98 import com.google.gwt.user.client.ui.HasVerticalAlignment;
99 import com.google.gwt.user.client.ui.HorizontalPanel;
100 import com.google.gwt.user.client.ui.HorizontalSplitPanel;
101 import com.google.gwt.user.client.ui.RootPanel;
102 import com.google.gwt.user.client.ui.VerticalPanel;
103 import com.google.gwt.view.client.SelectionChangeEvent;
104 import com.google.gwt.view.client.SelectionChangeEvent.Handler;
105 import com.google.gwt.view.client.SingleSelectionModel;
106
107 /**
108  * Entry point classes define <code>onModuleLoad()</code>.
109  */
110 public class Pithos implements EntryPoint, ResizeHandler {
111
112         public static final String HOME_CONTAINER = "pithos";
113
114         public static final String TRASH_CONTAINER = "trash";
115
116         public static final Configuration config = GWT.create(Configuration.class);
117         
118         /**
119          * Instantiate an application-level image bundle. This object will provide
120          * programmatic access to all the images needed by widgets.
121          */
122         static Images images = (Images) GWT.create(Images.class);
123
124     public String getUsername() {
125         return username;
126     }
127
128     public void setAccount(AccountResource acct) {
129         account = acct;
130     }
131
132     public AccountResource getAccount() {
133         return account;
134     }
135
136     public void updateFolder(Folder f, boolean showfiles, Command callback, final boolean openParent) {
137         folderTreeView.updateFolder(f, showfiles, callback, openParent);
138     }
139
140     public void updateGroupNode(Group group) {
141         groupTreeView.updateGroupNode(group);
142     }
143
144     public void updateMySharedRoot() {
145         mysharedTreeView.updateRoot();
146     }
147     
148     public void updateSharedFolder(Folder f, boolean showfiles) {
149         mysharedTreeView.updateFolder(f, showfiles);
150     }
151     
152     public void updateOtherSharedFolder(Folder f, boolean showfiles) {
153         otherSharedTreeView.updateFolder(f, showfiles);
154     }
155
156     public MysharedTreeView getMySharedTreeView() {
157         return mysharedTreeView;
158     }
159
160     /**
161          * An aggregate image bundle that pulls together all the images for this
162          * application into a single bundle.
163          */
164         public interface Images extends TopPanel.Images, FileList.Images, ToolsMenu.Images {
165
166                 @Source("gr/grnet/pithos/resources/document.png")
167                 ImageResource folders();
168
169                 @Source("gr/grnet/pithos/resources/advancedsettings.png")
170                 @ImageOptions(width=32, height=32)
171                 ImageResource tools();
172         }
173
174         private Throwable error;
175         
176         /**
177          * The Application Clipboard implementation;
178          */
179         private Clipboard clipboard = new Clipboard();
180
181         /**
182          * The top panel that contains the menu bar.
183          */
184         private TopPanel topPanel;
185
186         /**
187          * The panel that contains the various system messages.
188          */
189         private MessagePanel messagePanel = new MessagePanel(this, Pithos.images);
190
191         /**
192          * The bottom panel that contains the status bar.
193          */
194         private StatusPanel statusPanel = null;
195
196         /**
197          * The file list widget.
198          */
199         private FileList fileList;
200
201         /**
202          * The tab panel that occupies the right side of the screen.
203          */
204         private VerticalPanel inner = new VerticalPanel();
205
206
207         /**
208          * The split panel that will contain the left and right panels.
209          */
210         private HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
211
212         /**
213          * The currently selected item in the application, for use by the Edit menu
214          * commands. Potential types are Folder, File, User and Group.
215          */
216         private Object currentSelection;
217
218         public HashMap<String, String> userFullNameMap = new HashMap<String, String>();
219
220     private String username = null;
221
222     /**
223      * The authentication token of the current user.
224      */
225     private String token;
226
227     VerticalPanel trees;
228     
229     SingleSelectionModel<Folder> folderTreeSelectionModel;
230     FolderTreeViewModel folderTreeViewModel;
231     FolderTreeView folderTreeView;
232
233     SingleSelectionModel<Folder> mysharedTreeSelectionModel;
234     MysharedTreeViewModel mysharedTreeViewModel;
235     MysharedTreeView mysharedTreeView = null;;
236
237     protected SingleSelectionModel<Folder> otherSharedTreeSelectionModel;
238     OtherSharedTreeViewModel otherSharedTreeViewModel;
239     OtherSharedTreeView otherSharedTreeView = null;
240
241     GroupTreeViewModel groupTreeViewModel;
242     GroupTreeView groupTreeView;
243
244     TreeView selectedTree;
245     protected AccountResource account;
246     
247     Folder trash;
248     
249     List<Composite> treeViews = new ArrayList<Composite>();
250
251     @SuppressWarnings("rawtypes") List<SingleSelectionModel> selectionModels = new ArrayList<SingleSelectionModel>();
252     
253     public Button upload;
254     
255     private HTML numOfFiles;
256     
257     private Toolbar toolbar;
258     
259     private FileUploadDialog fileUploadDialog;
260     
261         @Override
262         public void onModuleLoad() {
263                 if (parseUserCredentials())
264             initialize();
265         }
266
267     private void initialize() {
268         boolean bareContent = Window.Location.getParameter("noframe") != null;
269         String contentWidth = bareContent ? "100%" : "75%";
270
271         VerticalPanel outer = new VerticalPanel();
272         outer.setWidth("100%");
273         if (!bareContent) {
274                 outer.addStyleName("pithos-outer");
275         }
276
277         if (!bareContent) {
278                 topPanel = new TopPanel(this, Pithos.images);
279                 topPanel.setWidth("100%");
280                 outer.add(topPanel);
281                 outer.setCellHorizontalAlignment(topPanel, HasHorizontalAlignment.ALIGN_CENTER);
282         }
283         
284         messagePanel.setVisible(false);
285         outer.add(messagePanel);
286         outer.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER);
287         outer.setCellVerticalAlignment(messagePanel, HasVerticalAlignment.ALIGN_MIDDLE);
288
289         HorizontalPanel header = new HorizontalPanel();
290         header.addStyleName("pithos-header");
291         header.setWidth(contentWidth);
292         if (bareContent)
293                 header.addStyleName("pithos-header-noframe");
294         upload = new Button("Upload", new ClickHandler() {
295             @Override
296             public void onClick(ClickEvent event) {
297                 if (getSelection() != null)
298                         new UploadFileCommand(Pithos.this, null, getSelection()).execute();
299             }
300         });
301         upload.addStyleName("pithos-uploadButton");
302         header.add(upload);
303         header.setCellHorizontalAlignment(upload, HasHorizontalAlignment.ALIGN_LEFT);
304         header.setCellVerticalAlignment(upload, HasVerticalAlignment.ALIGN_MIDDLE);
305
306         toolbar = new Toolbar(this);
307         header.add(toolbar);
308         header.setCellHorizontalAlignment(toolbar, HasHorizontalAlignment.ALIGN_CENTER);
309         header.setCellVerticalAlignment(toolbar, HasVerticalAlignment.ALIGN_MIDDLE);
310         
311         HorizontalPanel folderStatistics = new HorizontalPanel();
312         folderStatistics.addStyleName("pithos-folderStatistics");
313         numOfFiles = new HTML();
314         folderStatistics.add(numOfFiles);
315         folderStatistics.setCellVerticalAlignment(numOfFiles, HasVerticalAlignment.ALIGN_MIDDLE);
316         HTML numOfFilesLabel = new HTML("&nbsp;Files");
317         folderStatistics.add(numOfFilesLabel);
318         folderStatistics.setCellVerticalAlignment(numOfFilesLabel, HasVerticalAlignment.ALIGN_MIDDLE);
319         header.add(folderStatistics);
320         header.setCellHorizontalAlignment(folderStatistics, HasHorizontalAlignment.ALIGN_RIGHT);
321         header.setCellVerticalAlignment(folderStatistics, HasVerticalAlignment.ALIGN_MIDDLE);
322         header.setCellWidth(folderStatistics, "40px");
323         outer.add(header);
324         outer.setCellHorizontalAlignment(header, HasHorizontalAlignment.ALIGN_CENTER);
325         // Inner contains the various lists.nner
326         inner.sinkEvents(Event.ONCONTEXTMENU);
327         inner.setWidth("100%");
328
329         folderTreeSelectionModel = new SingleSelectionModel<Folder>();
330         folderTreeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
331             @Override
332             public void onSelectionChange(SelectionChangeEvent event) {
333                 if (folderTreeSelectionModel.getSelectedObject() != null) {
334                     deselectOthers(folderTreeView, folderTreeSelectionModel);
335                     applyPermissions(folderTreeSelectionModel.getSelectedObject());
336                     Folder f = folderTreeSelectionModel.getSelectedObject();
337                         updateFolder(f, true, new Command() {
338                                 
339                                 @Override
340                                 public void execute() {
341                                         updateStatistics();
342                                 }
343                         }, true);
344                         showRelevantToolbarButtons();
345                 }
346                                 else {
347                                         if (getSelectedTree().equals(folderTreeView))
348                                                 setSelectedTree(null);
349                                         if (getSelectedTree() == null)
350                                                 showRelevantToolbarButtons();
351                                 }
352             }
353         });
354         selectionModels.add(folderTreeSelectionModel);
355
356         folderTreeViewModel = new FolderTreeViewModel(this, folderTreeSelectionModel);
357         folderTreeView = new FolderTreeView(folderTreeViewModel);
358         treeViews.add(folderTreeView);
359         
360         fileList = new FileList(this, images);
361         inner.add(fileList);
362
363         inner.add(createUploadArea());
364         
365         trees = new VerticalPanel();
366         trees.setWidth("100%");
367         
368         // Add the left and right panels to the split panel.
369         splitPanel.setLeftWidget(trees);
370         splitPanel.setRightWidget(inner);
371         splitPanel.setSplitPosition("219px");
372         splitPanel.setSize("100%", "100%");
373         splitPanel.addStyleName("pithos-splitPanel");
374         splitPanel.setWidth(contentWidth);
375         outer.add(splitPanel);
376         outer.setCellHorizontalAlignment(splitPanel, HasHorizontalAlignment.ALIGN_CENTER);
377
378         if (!bareContent) {
379                 statusPanel = new StatusPanel();
380                 statusPanel.setWidth("100%");
381                 outer.add(statusPanel);
382                 outer.setCellHorizontalAlignment(statusPanel, HasHorizontalAlignment.ALIGN_CENTER);
383         }
384         else
385                 splitPanel.addStyleName("pithos-splitPanel-noframe");
386
387         // Hook the window resize event, so that we can adjust the UI.
388         Window.addResizeHandler(this);
389         // Clear out the window's built-in margin, because we want to take
390         // advantage of the entire client area.
391         Window.setMargin("0px");
392         // Finally, add the outer panel to the RootPanel, so that it will be
393         // displayed.
394         RootPanel.get().add(outer);
395         // Call the window resized handler to get the initial sizes setup. Doing
396         // this in a deferred command causes it to occur after all widgets'
397         // sizes have been computed by the browser.
398         Scheduler.get().scheduleDeferred(new ScheduledCommand() {
399
400             @Override
401             public void execute() {
402                 onWindowResized(Window.getClientHeight());
403             }
404         });
405
406         Scheduler.get().scheduleDeferred(new ScheduledCommand() {
407             @Override
408             public void execute() {
409                 fetchAccount(new Command() {
410                                         
411                                         @Override
412                                         public void execute() {
413                                 if (!account.hasHomeContainer())
414                                     createHomeContainer(account, this);
415                                 else if (!account.hasTrashContainer())
416                                         createTrashContainer(this);
417                                 else {
418                                         for (Folder f : account.getContainers())
419                                                 if (f.getName().equals(Pithos.TRASH_CONTAINER)) {
420                                                         trash = f;
421                                                         break;
422                                                 }
423                                     trees.add(folderTreeView);
424                                     folderTreeViewModel.initialize(account, new Command() {
425                                                                 
426                                                                 @Override
427                                                                 public void execute() {
428                                                     createMySharedTree();
429                                                                 }
430                                                         });
431
432                                     HorizontalPanel separator = new HorizontalPanel();
433                                     separator.addStyleName("pithos-statisticsSeparator");
434                                     separator.add(new HTML(""));
435                                     trees.add(separator);
436
437                                     groupTreeViewModel = new GroupTreeViewModel(Pithos.this);
438                                     groupTreeView = new GroupTreeView(groupTreeViewModel);
439                                     treeViews.add(groupTreeView);
440                                     trees.add(groupTreeView);
441                                     folderTreeView.showStatistics(account);
442                                 }
443                                         }
444                                 });
445             }
446         });
447         
448         Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
449                         
450                         @Override
451                         public boolean execute() {
452                                 Folder f = getSelection();
453                                 if (f != null) {
454                                         if (getSelectedTree().equals(folderTreeView))
455                                                 updateFolder(f, true, null, false);
456                                         else if (getSelectedTree().equals(mysharedTreeView))
457                                                 updateSharedFolder(f, true);
458                                 }
459                                 return true;
460                         }
461                 }, 3000);
462     }
463
464     public void applyPermissions(Folder f) {
465         if (f != null) {
466                 if (f.isInTrash()) {
467                         upload.setEnabled(false);
468                         hideUploadArea();
469                 }
470                 else {
471                         Boolean[] perms = f.getPermissions().get(username);
472                         if (f.getOwner().equals(username) || (perms != null && perms[1] != null && perms[1])) {
473                                 upload.setEnabled(true);
474                                 showUploadArea();
475                         }
476                         else {
477                                 upload.setEnabled(false);
478                                 hideUploadArea();
479                         }
480                 }
481         }
482         else {
483                 upload.setEnabled(false);
484                 hideUploadArea();
485         }
486         }
487
488         @SuppressWarnings({ "rawtypes", "unchecked" })
489         public void deselectOthers(TreeView _selectedTree, SingleSelectionModel model) {
490         selectedTree = _selectedTree;
491         
492         for (SingleSelectionModel s : selectionModels)
493             if (!s.equals(model) && s.getSelectedObject() != null)
494                 s.setSelected(s.getSelectedObject(), false);
495     }
496
497     public void showFiles(final Folder f) {
498         Set<File> files = f.getFiles();
499         showFiles(files);
500     }
501
502     public void showFiles(Set<File> files) {
503         fileList.setFiles(new ArrayList<File>(files));
504     }
505
506     /**
507          * Parse and store the user credentials to the appropriate fields.
508          */
509         private boolean parseUserCredentials() {
510         Configuration conf = (Configuration) GWT.create(Configuration.class);
511                 Dictionary otherProperties = Dictionary.getDictionary("otherProperties");
512         String cookie = otherProperties.get("authCookie");
513         String auth = Cookies.getCookie(cookie);
514         if (auth == null) {
515             authenticateUser();
516             return false;
517         }
518         if (auth.startsWith("\""))
519                 auth = auth.substring(1);
520         if (auth.endsWith("\""))
521                 auth = auth.substring(0, auth.length() - 1);
522                 String[] authSplit = auth.split("\\" + conf.cookieSeparator(), 2);
523                 if (authSplit.length != 2) {
524                     authenticateUser();
525                     return false;
526                 }
527                 username = authSplit[0];
528                 token = authSplit[1];
529
530         String gotoUrl = Window.Location.getParameter("goto");
531                 if (gotoUrl != null && gotoUrl.length() > 0) {
532                         Window.Location.assign(gotoUrl);
533                         return false;
534                 }
535                 return true;
536     }
537
538     /**
539          * Redirect the user to the login page for authentication.
540          */
541         protected void authenticateUser() {
542                 Dictionary otherProperties = Dictionary.getDictionary("otherProperties");
543         Window.Location.assign(otherProperties.get("loginUrl") + Window.Location.getHref());
544         }
545
546         protected void fetchAccount(final Command callback) {
547         String path = "?format=json";
548
549         GetRequest<AccountResource> getAccount = new GetRequest<AccountResource>(AccountResource.class, getApiPath(), username, path) {
550             @Override
551             public void onSuccess(AccountResource _result) {
552                 account = _result;
553                 if (callback != null)
554                         callback.execute();
555             }
556
557             @Override
558             public void onError(Throwable t) {
559                 GWT.log("Error getting account", t);
560                                 setError(t);
561                 if (t instanceof RestException)
562                     displayError("Error getting account: " + ((RestException) t).getHttpStatusText());
563                 else
564                     displayError("System error fetching user data: " + t.getMessage());
565             }
566
567                         @Override
568                         protected void onUnauthorized(Response response) {
569                                 sessionExpired();
570                         }
571         };
572         getAccount.setHeader("X-Auth-Token", token);
573         Scheduler.get().scheduleDeferred(getAccount);
574     }
575
576     public void updateStatistics() {
577         HeadRequest<AccountResource> headAccount = new HeadRequest<AccountResource>(AccountResource.class, getApiPath(), username, "", account) {
578
579                         @Override
580                         public void onSuccess(AccountResource _result) {
581                                 folderTreeView.showStatistics(account);
582                         }
583
584                         @Override
585                         public void onError(Throwable t) {
586                 GWT.log("Error getting account", t);
587                                 setError(t);
588                 if (t instanceof RestException)
589                     displayError("Error getting account: " + ((RestException) t).getHttpStatusText());
590                 else
591                     displayError("System error fetching user data: " + t.getMessage());
592                         }
593
594                         @Override
595                         protected void onUnauthorized(Response response) {
596                                 sessionExpired();
597                         }
598                 };
599                 headAccount.setHeader("X-Auth-Token", token);
600                 Scheduler.get().scheduleDeferred(headAccount);
601         }
602
603         protected void createHomeContainer(final AccountResource _account, final Command callback) {
604         String path = "/" + Pithos.HOME_CONTAINER;
605         PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
606             @Override
607             public void onSuccess(Resource result) {
608                 if (!_account.hasTrashContainer())
609                         createTrashContainer(callback);
610                 else
611                         fetchAccount(callback);
612             }
613
614             @Override
615             public void onError(Throwable t) {
616                 GWT.log("Error creating pithos", t);
617                                 setError(t);
618                 if (t instanceof RestException)
619                     displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText());
620                 else
621                     displayError("System error Error creating pithos: " + t.getMessage());
622             }
623
624                         @Override
625                         protected void onUnauthorized(Response response) {
626                                 sessionExpired();
627                         }
628         };
629         createPithos.setHeader("X-Auth-Token", getToken());
630         Scheduler.get().scheduleDeferred(createPithos);
631     }
632
633     protected void createTrashContainer(final Command callback) {
634         String path = "/" + Pithos.TRASH_CONTAINER;
635         PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
636             @Override
637             public void onSuccess(Resource result) {
638                         fetchAccount(callback);
639             }
640
641             @Override
642             public void onError(Throwable t) {
643                 GWT.log("Error creating pithos", t);
644                                 setError(t);
645                 if (t instanceof RestException)
646                     displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText());
647                 else
648                     displayError("System error Error creating pithos: " + t.getMessage());
649             }
650
651                         @Override
652                         protected void onUnauthorized(Response response) {
653                                 sessionExpired();
654                         }
655         };
656         createPithos.setHeader("X-Auth-Token", getToken());
657         Scheduler.get().scheduleDeferred(createPithos);
658     }
659
660     /**
661          * Creates an HTML fragment that places an image & caption together, for use
662          * in a group header.
663          *
664          * @param imageProto an image prototype for an image
665          * @param caption the group caption
666          * @return the header HTML fragment
667          */
668         private String createHeaderHTML(AbstractImagePrototype imageProto, String caption) {
669                 String captionHTML = "<table class='caption' cellpadding='0' " 
670                 + "cellspacing='0'>" + "<tr><td class='lcaption'>" + imageProto.getHTML() 
671                 + "</td><td id =" + caption +" class='rcaption'><b style='white-space:nowrap'>&nbsp;" 
672                 + caption + "</b></td></tr></table>";
673                 return captionHTML;
674         }
675
676         protected void onWindowResized(int height) {
677                 // Adjust the split panel to take up the available room in the window.
678                 int newHeight = height - splitPanel.getAbsoluteTop();
679                 if (newHeight < 1)
680                         newHeight = 1;
681                 splitPanel.setHeight("" + newHeight);
682                 inner.setHeight("" + newHeight);
683         }
684
685         @Override
686         public void onResize(ResizeEvent event) {
687                 int height = event.getHeight();
688                 onWindowResized(height);
689         }
690
691         /**
692          * Display an error message.
693          *
694          * @param msg the message to display
695          */
696         public void displayError(String msg) {
697                 messagePanel.displayError(msg);
698         }
699
700         /**
701          * Display a warning message.
702          *
703          * @param msg the message to display
704          */
705         public void displayWarning(String msg) {
706                 messagePanel.displayWarning(msg);
707         }
708
709         /**
710          * Display an informational message.
711          *
712          * @param msg the message to display
713          */
714         public void displayInformation(String msg) {
715                 messagePanel.displayInformation(msg);
716         }
717
718         /**
719          * Retrieve the fileList.
720          *
721          * @return the fileList
722          */
723         public FileList getFileList() {
724                 return fileList;
725         }
726
727         /**
728          * Retrieve the topPanel.
729          *
730          * @return the topPanel
731          */
732         TopPanel getTopPanel() {
733                 return topPanel;
734         }
735
736         /**
737          * Retrieve the clipboard.
738          *
739          * @return the clipboard
740          */
741         public Clipboard getClipboard() {
742                 return clipboard;
743         }
744
745         public StatusPanel getStatusPanel() {
746                 return statusPanel;
747         }
748
749         public String getToken() {
750                 return token;
751         }
752
753         public static native void preventIESelection() /*-{
754                 $doc.body.onselectstart = function () { return false; };
755         }-*/;
756
757         public static native void enableIESelection() /*-{
758                 if ($doc.body.onselectstart != null)
759                 $doc.body.onselectstart = null;
760         }-*/;
761
762         /**
763          * @return the absolute path of the API root URL
764          */
765         public String getApiPath() {
766                 Configuration conf = (Configuration) GWT.create(Configuration.class);
767                 return conf.apiPath();
768         }
769
770         /**
771          * History support for folder navigation
772          * adds a new browser history entry
773          *
774          * @param key
775          */
776         public void updateHistory(String key){
777 //              Replace any whitespace of the initial string to "+"
778 //              String result = key.replaceAll("\\s","+");
779 //              Add a new browser history entry.
780 //              History.newItem(result);
781                 History.newItem(key);
782         }
783
784     public void deleteFolder(final Folder folder, final Command callback) {
785         String path = getApiPath() + folder.getOwner() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(folder.getPrefix()) + "&t=" + System.currentTimeMillis();
786         RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
787         builder.setHeader("X-Auth-Token", getToken());
788         try {
789             builder.sendRequest("", new RequestCallback() {
790                 @Override
791                 public void onResponseReceived(Request request, Response response) {
792                     if (response.getStatusCode() == Response.SC_OK) {
793                         JSONValue json = JSONParser.parseStrict(response.getText());
794                         JSONArray array = json.isArray();
795                         int i = 0;
796                         if (array != null) {
797                             deleteObject(folder, i, array, callback);
798                         }
799                     }
800                 }
801
802                 @Override
803                 public void onError(Request request, Throwable exception) {
804                         setError(exception);
805                     displayError("System error unable to delete folder: " + exception.getMessage());
806                 }
807             });
808         }
809         catch (RequestException e) {
810         }
811     }
812
813     void deleteObject(final Folder folder, final int i, final JSONArray array, final Command callback) {
814         if (i < array.size()) {
815             JSONObject o = array.get(i).isObject();
816             if (o != null && !o.containsKey("subdir")) {
817                 JSONString name = o.get("name").isString();
818                 String path = "/" + folder.getContainer() + "/" + name.stringValue();
819                 DeleteRequest delete = new DeleteRequest(getApiPath(), folder.getOwner(), URL.encode(path)) {
820                     @Override
821                     public void onSuccess(Resource result) {
822                         deleteObject(folder, i + 1, array, callback);
823                     }
824
825                     @Override
826                     public void onError(Throwable t) {
827                         GWT.log("", t);
828                                                 setError(t);
829                         displayError("System error unable to delete folder: " + t.getMessage());
830                     }
831
832                                 @Override
833                                 protected void onUnauthorized(Response response) {
834                                         sessionExpired();
835                                 }
836                 };
837                 delete.setHeader("X-Auth-Token", getToken());
838                 Scheduler.get().scheduleDeferred(delete);
839             }
840             else if (o != null) {
841                 String subdir = o.get("subdir").isString().stringValue();
842                 subdir = subdir.substring(0, subdir.length() - 1);
843                 String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(subdir) + "&t=" + System.currentTimeMillis();
844                 RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
845                 builder.setHeader("X-Auth-Token", getToken());
846                 try {
847                     builder.sendRequest("", new RequestCallback() {
848                         @Override
849                         public void onResponseReceived(Request request, Response response) {
850                             if (response.getStatusCode() == Response.SC_OK) {
851                                 JSONValue json = JSONParser.parseStrict(response.getText());
852                                 JSONArray array2 = json.isArray();
853                                 if (array2 != null) {
854                                     int l = array.size();
855                                     for (int j=0; j<array2.size(); j++) {
856                                         array.set(l++, array2.get(j));
857                                     }
858                                 }
859                                 deleteObject(folder, i + 1, array, callback);
860                             }
861                         }
862
863                         @Override
864                         public void onError(Request request, Throwable exception) {
865                                 setError(exception);
866                             displayError("System error unable to delete folder: " + exception.getMessage());
867                         }
868                     });
869                 }
870                 catch (RequestException e) {
871                 }
872             }
873         }
874         else {
875             String path = folder.getUri();
876             DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), URL.encode(path)) {
877                 @Override
878                 public void onSuccess(Resource result) {
879                     updateFolder(folder.getParent(), true, new Command() {
880                                                 
881                                                 @Override
882                                                 public void execute() {
883                                                         folderTreeSelectionModel.setSelected(folder.getParent(), true);
884                                                         updateStatistics();
885                                                         if (callback != null)
886                                                                 callback.execute();
887                                                 }
888                                         }, true);
889                 }
890
891                 @Override
892                 public void onError(Throwable t) {
893                     GWT.log("", t);
894                                         setError(t);
895                     if (t instanceof RestException) {
896                         if (((RestException) t).getHttpStatusCode() != Response.SC_NOT_FOUND)
897                                 displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText());
898                         else
899                                 onSuccess(null);
900                     }
901                     else
902                         displayError("System error unable to delete folder: " + t.getMessage());
903                 }
904
905                                 @Override
906                                 protected void onUnauthorized(Response response) {
907                                         sessionExpired();
908                                 }
909             };
910             deleteFolder.setHeader("X-Auth-Token", getToken());
911             Scheduler.get().scheduleDeferred(deleteFolder);
912         }
913     }
914
915     public FolderTreeView getFolderTreeView() {
916         return folderTreeView;
917     }
918
919     public void copyFiles(final Iterator<File> iter, final String targetUsername, final String targetUri, final Command callback) {
920         if (iter.hasNext()) {
921             File file = iter.next();
922             String path = targetUri + "/" + file.getName();
923             PutRequest copyFile = new PutRequest(getApiPath(), targetUsername, path) {
924                 @Override
925                 public void onSuccess(Resource result) {
926                     copyFiles(iter, targetUsername, targetUri, callback);
927                 }
928
929                 @Override
930                 public void onError(Throwable t) {
931                     GWT.log("", t);
932                                         setError(t);
933                     if (t instanceof RestException) {
934                         displayError("Unable to copy file: " + ((RestException) t).getHttpStatusText());
935                     }
936                     else
937                         displayError("System error unable to copy file: "+t.getMessage());
938                 }
939
940                                 @Override
941                                 protected void onUnauthorized(Response response) {
942                                         sessionExpired();
943                                 }
944             };
945             copyFile.setHeader("X-Auth-Token", getToken());
946             copyFile.setHeader("X-Copy-From", URL.encodePathSegment(file.getUri()));
947             if (!file.getOwner().equals(targetUsername))
948                 copyFile.setHeader("X-Source-Account", URL.encodePathSegment(file.getOwner()));
949             copyFile.setHeader("Content-Type", file.getContentType());
950             Scheduler.get().scheduleDeferred(copyFile);
951         }
952         else  if (callback != null) {
953             callback.execute();
954         }
955     }
956
957     public void copySubfolders(final Iterator<Folder> iter, final String targetUsername, final String targetUri, final Command callback) {
958         if (iter.hasNext()) {
959             final Folder f = iter.next();
960             copyFolder(f, targetUsername, targetUri, new Command() {
961                                 
962                                 @Override
963                                 public void execute() {
964                                         copySubfolders(iter, targetUsername, targetUri, callback);
965                                 }
966                         });
967         }
968         else  if (callback != null) {
969             callback.execute();
970         }
971     }
972
973     public void copyFolder(final Folder f, final String targetUsername, final String targetUri, final Command callback) {
974         String path = targetUri + "/" + f.getName();
975         PutRequest createFolder = new PutRequest(getApiPath(), targetUsername, path) {
976             @Override
977             public void onSuccess(Resource result) {
978                 GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, getApiPath(), f.getOwner(), "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(f.getPrefix()), f) {
979
980                                         @Override
981                                         public void onSuccess(final Folder _f) {
982                                 Iterator<File> iter = _f.getFiles().iterator();
983                                 copyFiles(iter, targetUsername, targetUri + "/" + _f.getName(), new Command() {
984                                     @Override
985                                     public void execute() {
986                                         Iterator<Folder> iterf = _f.getSubfolders().iterator();
987                                         copySubfolders(iterf, targetUsername, targetUri + "/" + _f.getName(), callback);
988                                     }
989                                 });
990                                         }
991
992                                         @Override
993                                         public void onError(Throwable t) {
994                                 GWT.log("", t);
995                                                 setError(t);
996                                 if (t instanceof RestException) {
997                                     displayError("Unable to get folder: " + ((RestException) t).getHttpStatusText());
998                                 }
999                                 else
1000                                     displayError("System error getting folder: " + t.getMessage());
1001                                         }
1002
1003                                         @Override
1004                                         protected void onUnauthorized(Response response) {
1005                                                 sessionExpired();
1006                                         }
1007                                 };
1008                                 getFolder.setHeader("X-Auth-Token", getToken());
1009                                 Scheduler.get().scheduleDeferred(getFolder);
1010             }
1011
1012             @Override
1013             public void onError(Throwable t) {
1014                 GWT.log("", t);
1015                                 setError(t);
1016                if (t instanceof RestException) {
1017                     displayError("Unable to create folder: " + ((RestException) t).getHttpStatusText());
1018                 }
1019                 else
1020                     displayError("System error creating folder: " + t.getMessage());
1021             }
1022
1023                         @Override
1024                         protected void onUnauthorized(Response response) {
1025                                 sessionExpired();
1026                         }
1027         };
1028         createFolder.setHeader("X-Auth-Token", getToken());
1029         createFolder.setHeader("Accept", "*/*");
1030         createFolder.setHeader("Content-Length", "0");
1031         createFolder.setHeader("Content-Type", "application/folder");
1032         Scheduler.get().scheduleDeferred(createFolder);
1033     }
1034     
1035     public void addSelectionModel(@SuppressWarnings("rawtypes") SingleSelectionModel model) {
1036         selectionModels.add(model);
1037     }
1038
1039         public OtherSharedTreeView getOtherSharedTreeView() {
1040                 return otherSharedTreeView;
1041         }
1042
1043         public void updateTrash(boolean showFiles, Command callback) {
1044                 updateFolder(trash, showFiles, callback, true);
1045         }
1046
1047         public void updateGroupsNode() {
1048                 groupTreeView.updateGroupNode(null);
1049         }
1050
1051         public void addGroup(String groupname) {
1052                 Group newGroup = new Group(groupname);
1053                 account.addGroup(newGroup);
1054                 groupTreeView.updateGroupNode(null);
1055         }
1056
1057         public void removeGroup(Group group) {
1058                 account.removeGroup(group);
1059                 updateGroupsNode();
1060         }
1061
1062         public TreeView getSelectedTree() {
1063                 return selectedTree;
1064         }
1065         
1066         public void setSelectedTree(TreeView selected) {
1067                 selectedTree = selected;
1068         }
1069
1070         public Folder getSelection() {
1071                 if (selectedTree != null)
1072                         return selectedTree.getSelection();
1073                 return null;
1074         }
1075
1076         public void showFolderStatistics(int folderFileCount) {
1077                 numOfFiles.setHTML(String.valueOf(folderFileCount));
1078         }
1079
1080         public GroupTreeView getGroupTreeView() {
1081                 return groupTreeView;
1082         }
1083
1084         public void sessionExpired() {
1085                 new SessionExpiredDialog(this).center();
1086         }
1087
1088         public void updateRootFolder(Command callback) {
1089                 updateFolder(account.getPithos(), false, callback, true);
1090         }
1091
1092         void createMySharedTree() {
1093                 mysharedTreeSelectionModel = new SingleSelectionModel<Folder>();
1094                 mysharedTreeSelectionModel.addSelectionChangeHandler(new Handler() {
1095                     @Override
1096                     public void onSelectionChange(SelectionChangeEvent event) {
1097                         if (mysharedTreeSelectionModel.getSelectedObject() != null) {
1098                             deselectOthers(mysharedTreeView, mysharedTreeSelectionModel);
1099                             upload.setEnabled(false);
1100                             hideUploadArea();
1101                             updateSharedFolder(mysharedTreeSelectionModel.getSelectedObject(), true);
1102                                         showRelevantToolbarButtons();
1103                         }
1104                                 else {
1105                                         if (getSelectedTree().equals(mysharedTreeView))
1106                                                 setSelectedTree(null);
1107                                         if (getSelectedTree() == null)
1108                                                 showRelevantToolbarButtons();
1109                                 }
1110                     }
1111                 });
1112                 selectionModels.add(mysharedTreeSelectionModel);
1113                 mysharedTreeViewModel = new MysharedTreeViewModel(Pithos.this, mysharedTreeSelectionModel);
1114                 mysharedTreeViewModel.initialize(new Command() {
1115                         
1116                         @Override
1117                         public void execute() {
1118                             mysharedTreeView = new MysharedTreeView(mysharedTreeViewModel);
1119                                 trees.insert(mysharedTreeView, 2);
1120                                 treeViews.add(mysharedTreeView);
1121                                 createOtherSharedTree();
1122                         }
1123                 });
1124         }
1125
1126         void createOtherSharedTree() {
1127                 otherSharedTreeSelectionModel = new SingleSelectionModel<Folder>();
1128                 otherSharedTreeSelectionModel.addSelectionChangeHandler(new Handler() {
1129                     @Override
1130                     public void onSelectionChange(SelectionChangeEvent event) {
1131                         if (otherSharedTreeSelectionModel.getSelectedObject() != null) {
1132                             deselectOthers(otherSharedTreeView, otherSharedTreeSelectionModel);
1133                             applyPermissions(otherSharedTreeSelectionModel.getSelectedObject());
1134                             updateOtherSharedFolder(otherSharedTreeSelectionModel.getSelectedObject(), true);
1135                                         showRelevantToolbarButtons();
1136                         }
1137                                 else {
1138                                         if (getSelectedTree().equals(otherSharedTreeView))
1139                                                 setSelectedTree(null);
1140                                         if (getSelectedTree() == null)
1141                                                 showRelevantToolbarButtons();
1142                                 }
1143                     }
1144                 });
1145                 selectionModels.add(otherSharedTreeSelectionModel);
1146                 otherSharedTreeViewModel = new OtherSharedTreeViewModel(Pithos.this, otherSharedTreeSelectionModel);
1147                 otherSharedTreeViewModel.initialize(new Command() {
1148                         
1149                         @Override
1150                         public void execute() {
1151                             otherSharedTreeView = new OtherSharedTreeView(otherSharedTreeViewModel);
1152                                 trees.insert(otherSharedTreeView, 1);
1153                                 treeViews.add(otherSharedTreeView);
1154                         }
1155                 });
1156         }
1157
1158         public native void log1(String message)/*-{
1159                 $wnd.console.log(message);
1160         }-*/;
1161
1162         public String getErrorData() {
1163                 if (error != null)
1164                         return error.toString();
1165                 return "";
1166         }
1167         
1168         public void setError(Throwable t) {
1169                 error = t;
1170         }
1171         
1172         public void showRelevantToolbarButtons() {
1173                 toolbar.showRelevantButtons();
1174         }
1175
1176         public FileUploadDialog getFileUploadDialog() {
1177                 if (fileUploadDialog == null)
1178                         fileUploadDialog = new FileUploadDialog(this);
1179                 return fileUploadDialog;
1180         }
1181
1182         public void hideUploadIndicator() {
1183                 upload.removeStyleName("pithos-uploadButton-loading");
1184                 upload.setTitle("");
1185         }
1186         
1187         public void showUploadIndicator() {
1188                 upload.addStyleName("pithos-uploadButton-loading");
1189                 upload.setTitle("Upload in progress. Click for details.");
1190         }
1191
1192         public void scheduleFolderHeadCommand(final Folder folder, final Command callback) {
1193                 if (folder == null) {
1194                         if (callback != null)
1195                                 callback.execute();
1196                 }
1197                 else {
1198                         HeadRequest<Folder> headFolder = new HeadRequest<Folder>(Folder.class, getApiPath(), folder.getOwner(), folder.getUri(), folder) {
1199         
1200                                 @Override
1201                                 public void onSuccess(Folder _result) {
1202                                         if (callback != null)
1203                                                 callback.execute();
1204                                 }
1205         
1206                                 @Override
1207                                 public void onError(Throwable t) {
1208                                 if (t instanceof RestException) {
1209                                         if (((RestException) t).getHttpStatusCode() == Response.SC_NOT_FOUND) {
1210                                 final String path = folder.getUri();
1211                                 PutRequest newFolder = new PutRequest(getApiPath(), folder.getOwner(), path) {
1212                                     @Override
1213                                     public void onSuccess(Resource _result) {
1214                                         scheduleFolderHeadCommand(folder, callback);
1215                                     }
1216         
1217                                     @Override
1218                                     public void onError(Throwable _t) {
1219                                         GWT.log("", _t);
1220                                                                 setError(_t);
1221                                         if(_t instanceof RestException){
1222                                             displayError("Unable to create folder: " + ((RestException) _t).getHttpStatusText());
1223                                         }
1224                                         else
1225                                             displayError("System error creating folder: " + _t.getMessage());
1226                                     }
1227         
1228                                                 @Override
1229                                                 protected void onUnauthorized(Response response) {
1230                                                         sessionExpired();
1231                                                 }
1232                                 };
1233                                 newFolder.setHeader("X-Auth-Token", getToken());
1234                                 newFolder.setHeader("Content-Type", "application/folder");
1235                                 newFolder.setHeader("Accept", "*/*");
1236                                 newFolder.setHeader("Content-Length", "0");
1237                                 Scheduler.get().scheduleDeferred(newFolder);
1238                                         }
1239                                         else
1240                                                 displayError("Error heading folder: " + ((RestException) t).getHttpStatusText());
1241                                 }
1242                                 else
1243                                     displayError("System error heading folder: " + t.getMessage());
1244         
1245                                 GWT.log("Error heading folder", t);
1246                                         setError(t);
1247                                 }
1248         
1249                                 @Override
1250                                 protected void onUnauthorized(Response response) {
1251                                         sessionExpired();
1252                                 }
1253                         };
1254                         headFolder.setHeader("X-Auth-Token", getToken());
1255                         Scheduler.get().scheduleDeferred(headFolder);
1256                 }
1257         }
1258
1259         public void scheduleFileHeadCommand(File f, final Command callback) {
1260                 HeadRequest<File> headFile = new HeadRequest<File>(File.class, getApiPath(), f.getOwner(), f.getUri(), f) {
1261
1262                         @Override
1263                         public void onSuccess(File _result) {
1264                                 if (callback != null)
1265                                         callback.execute();
1266                         }
1267
1268                         @Override
1269                         public void onError(Throwable t) {
1270                         GWT.log("Error heading file", t);
1271                                 setError(t);
1272                         if (t instanceof RestException)
1273                             displayError("Error heading file: " + ((RestException) t).getHttpStatusText());
1274                         else
1275                             displayError("System error heading file: " + t.getMessage());
1276                         }
1277
1278                         @Override
1279                         protected void onUnauthorized(Response response) {
1280                                 sessionExpired();
1281                         }
1282                 };
1283                 headFile.setHeader("X-Auth-Token", getToken());
1284                 Scheduler.get().scheduleDeferred(headFile);
1285         }
1286
1287         public boolean isMySharedSelected() {
1288                 return getSelectedTree().equals(getMySharedTreeView());
1289         }
1290         
1291         private FlowPanel createUploadArea() {
1292                 FlowPanel area = new FlowPanel();
1293                 area.getElement().setId("container");
1294                 HTML list = new HTML();
1295                 list.getElement().setId("filelist");
1296                 area.add(list);
1297                 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
1298                         
1299                         @Override
1300                         public void execute() {
1301                                 setupUploadArea(Pithos.this, getToken());
1302                         }
1303                 });
1304                 
1305                 return area;
1306         }
1307         
1308         native void setupUploadArea(Pithos app, String token) /*-{
1309                 $wnd.$("#container").pluploadQueue({
1310                         // General settings
1311                         runtimes : 'html5',
1312                         unique_names : true,
1313                         multiple_queues: true,
1314                         drop_element: 'filelist',
1315                         
1316                         preinit: {
1317                                 Init: function(up, info) {
1318                                         if ($wnd.console && $wnd.console.log)
1319                                                 $wnd.console.log("Init fired");
1320                                         up.settings.file_data_name = "X-Object-Data";                           
1321                                 }
1322                         },
1323                         
1324                         init: {
1325                                 FilesAdded: function(up, files) {
1326                                         $wnd.$('#container').css('border', '');
1327                                         var api = app.@gr.grnet.pithos.web.client.Pithos::getApiPath()();
1328                                         var folder = app.@gr.grnet.pithos.web.client.Pithos::getUploadFolder()();
1329                                         var owner = folder.@gr.grnet.pithos.web.client.foldertree.Folder::getOwner()();
1330                                         var uri = folder.@gr.grnet.pithos.web.client.foldertree.Folder::getUri()();
1331                                         var path = api + owner + uri;
1332                                         for (var j=0; j<files.length; j++) {
1333                                                 files[j].folder = folder;
1334                                                 files[j].url = path + "/" + files[j].name + "?X-Auth-Token=" + encodeURIComponent(token);
1335                                         }
1336                                         up.start();
1337                                 },
1338                                 
1339                                 BeforeUpload: function(up, file) {
1340                                         if ($wnd.console && $wnd.console.log)
1341                                                 $wnd.console.log('About to upload ' + file.url);
1342                                         up.settings.url = file.url;
1343                                 },
1344                                 
1345                                 FileUploaded: function(up, file, response) {
1346                                         if ($wnd.console && $wnd.console.log) {
1347                                                 $wnd.console.log('File ' + file.name + ' uploaded');
1348                                                 $wnd.console.log('Response: ' + response);
1349                                         }
1350                                         up.removeFile(file);
1351                                         var folder = app.@gr.grnet.pithos.web.client.Pithos::getUploadFolder()();
1352                                         if (folder == file.folder)
1353                                                 app.@gr.grnet.pithos.web.client.Pithos::updateUploadFolder()();
1354                                 },
1355                                 
1356                                 UploadComplete: function(up, files) {
1357                                         if ($wnd.console && $wnd.console.log)
1358                                                 $wnd.console.log('All files finished');
1359                                 },
1360                                 
1361                                 Error: function(up, error) {
1362                                         if ($wnd.console && $wnd.console.log)
1363                                                 $wnd.console.log("Error occured:" + error);
1364                                 }
1365                         }
1366                 });
1367                 var uploader = $wnd.$("#container").pluploadQueue();
1368                 if (uploader.runtime != 'html5')
1369                         $wnd.$("#container").hide();
1370                 else {
1371                         if ($wnd.console && $wnd.console.log) {
1372                                 $wnd.console.log(uploader);
1373                                 $wnd.console.log($wnd.plupload);
1374                         }
1375                         $wnd.$('.plupload_header').hide();
1376                         $wnd.$('.plupload_filelist_header').hide();
1377                         $wnd.$('#container_filelist').css('overflow-y', 'auto');
1378                         $wnd.$('.plupload_filelist_footer').hide();
1379                         $wnd.document.getElementById('container').addEventListener('dragenter', function(event) {
1380                                 $wnd.$('#container').css('border', '3px inset');
1381                         }, false);
1382                         $wnd.document.getElementById('container').addEventListener('dragleave', function(event) {
1383                                 $wnd.$('#container').css('border', '');
1384                         }, false);
1385                 }
1386         }-*/;
1387         
1388         private Folder getUploadFolder() {
1389                 if (folderTreeView.equals(getSelectedTree()) || otherSharedTreeView.equals(getSelectedTree())) {
1390                         return getSelection();
1391                 }
1392                 return null;
1393         }
1394         
1395         private void updateUploadFolder() {
1396                 if (folderTreeView.equals(getSelectedTree()) || otherSharedTreeView.equals(getSelectedTree())) {
1397                         Folder f = getSelection();
1398                         if (getSelectedTree().equals(getFolderTreeView()))
1399                                 updateFolder(f, true, new Command() {
1400                                 
1401                                         @Override
1402                                         public void execute() {
1403                                                 updateStatistics();
1404                                         }
1405                                 }, false);
1406                         else
1407                                 updateOtherSharedFolder(f, true);
1408                 }
1409         }
1410
1411         public native void hideUploadArea() /*-{
1412                 $wnd.$("#container").hide();
1413         }-*/;
1414
1415         public native void showUploadArea() /*-{
1416                 $wnd.$("#container").show();
1417         }-*/;
1418 }