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