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