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