Fixed offset of context menu when the page had been scrolled (issue #2436)
[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         private 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         }
748
749         /**
750          * Display a warning message.
751          *
752          * @param msg the message to display
753          */
754         public void displayWarning(String msg) {
755                 messagePanel.displayWarning(msg);
756         }
757
758         /**
759          * Display an informational message.
760          *
761          * @param msg the message to display
762          */
763         public void displayInformation(String msg) {
764                 messagePanel.displayInformation(msg);
765         }
766
767         /**
768          * Retrieve the fileList.
769          *
770          * @return the fileList
771          */
772         public FileList getFileList() {
773                 return fileList;
774         }
775
776         /**
777          * Retrieve the topPanel.
778          *
779          * @return the topPanel
780          */
781         TopPanel getTopPanel() {
782                 return topPanel;
783         }
784
785         /**
786          * Retrieve the clipboard.
787          *
788          * @return the clipboard
789          */
790         public Clipboard getClipboard() {
791                 return clipboard;
792         }
793
794         public StatusPanel getStatusPanel() {
795                 return statusPanel;
796         }
797
798         public String getToken() {
799                 return token;
800         }
801
802         public static native void preventIESelection() /*-{
803                 $doc.body.onselectstart = function () { return false; };
804         }-*/;
805
806         public static native void enableIESelection() /*-{
807                 if ($doc.body.onselectstart != null)
808                 $doc.body.onselectstart = null;
809         }-*/;
810
811         /**
812          * @return the absolute path of the API root URL
813          */
814         public String getApiPath() {
815                 Configuration conf = (Configuration) GWT.create(Configuration.class);
816                 return conf.apiPath();
817         }
818
819         /**
820          * History support for folder navigation
821          * adds a new browser history entry
822          *
823          * @param key
824          */
825         public void updateHistory(String key){
826 //              Replace any whitespace of the initial string to "+"
827 //              String result = key.replaceAll("\\s","+");
828 //              Add a new browser history entry.
829 //              History.newItem(result);
830                 History.newItem(key);
831         }
832
833     public void deleteFolder(final Folder folder, final Command callback) {
834         String path = getApiPath() + folder.getOwner() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(folder.getPrefix()) + "&t=" + System.currentTimeMillis();
835         RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
836         builder.setHeader("X-Auth-Token", getToken());
837         try {
838             builder.sendRequest("", new RequestCallback() {
839                 @Override
840                 public void onResponseReceived(Request request, Response response) {
841                     if (response.getStatusCode() == Response.SC_OK) {
842                         JSONValue json = JSONParser.parseStrict(response.getText());
843                         JSONArray array = json.isArray();
844                         int i = 0;
845                         if (array != null) {
846                             deleteObject(folder, i, array, callback);
847                         }
848                     }
849                 }
850
851                 @Override
852                 public void onError(Request request, Throwable exception) {
853                         setError(exception);
854                     displayError("System error unable to delete folder: " + exception.getMessage());
855                 }
856             });
857         }
858         catch (RequestException e) {
859         }
860     }
861
862     void deleteObject(final Folder folder, final int i, final JSONArray array, final Command callback) {
863         if (i < array.size()) {
864             JSONObject o = array.get(i).isObject();
865             if (o != null && !o.containsKey("subdir")) {
866                 JSONString name = o.get("name").isString();
867                 String path = "/" + folder.getContainer() + "/" + name.stringValue();
868                 DeleteRequest delete = new DeleteRequest(getApiPath(), folder.getOwner(), URL.encode(path)) {
869                     @Override
870                     public void onSuccess(Resource result) {
871                         deleteObject(folder, i + 1, array, callback);
872                     }
873
874                     @Override
875                     public void onError(Throwable t) {
876                         GWT.log("", t);
877                                                 setError(t);
878                         displayError("System error unable to delete folder: " + t.getMessage());
879                     }
880
881                                 @Override
882                                 protected void onUnauthorized(Response response) {
883                                         sessionExpired();
884                                 }
885                 };
886                 delete.setHeader("X-Auth-Token", getToken());
887                 Scheduler.get().scheduleDeferred(delete);
888             }
889             else if (o != null) {
890                 String subdir = o.get("subdir").isString().stringValue();
891                 subdir = subdir.substring(0, subdir.length() - 1);
892                 String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(subdir) + "&t=" + System.currentTimeMillis();
893                 RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
894                 builder.setHeader("X-Auth-Token", getToken());
895                 try {
896                     builder.sendRequest("", new RequestCallback() {
897                         @Override
898                         public void onResponseReceived(Request request, Response response) {
899                             if (response.getStatusCode() == Response.SC_OK) {
900                                 JSONValue json = JSONParser.parseStrict(response.getText());
901                                 JSONArray array2 = json.isArray();
902                                 if (array2 != null) {
903                                     int l = array.size();
904                                     for (int j=0; j<array2.size(); j++) {
905                                         array.set(l++, array2.get(j));
906                                     }
907                                 }
908                                 deleteObject(folder, i + 1, array, callback);
909                             }
910                         }
911
912                         @Override
913                         public void onError(Request request, Throwable exception) {
914                                 setError(exception);
915                             displayError("System error unable to delete folder: " + exception.getMessage());
916                         }
917                     });
918                 }
919                 catch (RequestException e) {
920                 }
921             }
922         }
923         else {
924             String path = folder.getUri();
925             DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), URL.encode(path)) {
926                 @Override
927                 public void onSuccess(Resource result) {
928                     updateFolder(folder.getParent(), true, new Command() {
929                                                 
930                                                 @Override
931                                                 public void execute() {
932                                                         folderTreeSelectionModel.setSelected(folder.getParent(), true);
933                                                         updateStatistics();
934                                                         if (callback != null)
935                                                                 callback.execute();
936                                                 }
937                                         }, true);
938                 }
939
940                 @Override
941                 public void onError(Throwable t) {
942                     GWT.log("", t);
943                                         setError(t);
944                     if (t instanceof RestException) {
945                         if (((RestException) t).getHttpStatusCode() != Response.SC_NOT_FOUND)
946                                 displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText());
947                         else
948                                 onSuccess(null);
949                     }
950                     else
951                         displayError("System error unable to delete folder: " + t.getMessage());
952                 }
953
954                                 @Override
955                                 protected void onUnauthorized(Response response) {
956                                         sessionExpired();
957                                 }
958             };
959             deleteFolder.setHeader("X-Auth-Token", getToken());
960             Scheduler.get().scheduleDeferred(deleteFolder);
961         }
962     }
963
964     public FolderTreeView getFolderTreeView() {
965         return folderTreeView;
966     }
967
968     public void copyFiles(final Iterator<File> iter, final String targetUsername, final String targetUri, final Command callback) {
969         if (iter.hasNext()) {
970             File file = iter.next();
971             String path = targetUri + "/" + file.getName();
972             PutRequest copyFile = new PutRequest(getApiPath(), targetUsername, path) {
973                 @Override
974                 public void onSuccess(Resource result) {
975                     copyFiles(iter, targetUsername, targetUri, callback);
976                 }
977
978                 @Override
979                 public void onError(Throwable t) {
980                     GWT.log("", t);
981                                         setError(t);
982                     if (t instanceof RestException) {
983                         displayError("Unable to copy file: " + ((RestException) t).getHttpStatusText());
984                     }
985                     else
986                         displayError("System error unable to copy file: "+t.getMessage());
987                 }
988
989                                 @Override
990                                 protected void onUnauthorized(Response response) {
991                                         sessionExpired();
992                                 }
993             };
994             copyFile.setHeader("X-Auth-Token", getToken());
995             copyFile.setHeader("X-Copy-From", URL.encodePathSegment(file.getUri()));
996             if (!file.getOwner().equals(targetUsername))
997                 copyFile.setHeader("X-Source-Account", URL.encodePathSegment(file.getOwner()));
998             copyFile.setHeader("Content-Type", file.getContentType());
999             Scheduler.get().scheduleDeferred(copyFile);
1000         }
1001         else  if (callback != null) {
1002             callback.execute();
1003         }
1004     }
1005
1006     public void copySubfolders(final Iterator<Folder> iter, final String targetUsername, final String targetUri, final Command callback) {
1007         if (iter.hasNext()) {
1008             final Folder f = iter.next();
1009             copyFolder(f, targetUsername, targetUri, new Command() {
1010                                 
1011                                 @Override
1012                                 public void execute() {
1013                                         copySubfolders(iter, targetUsername, targetUri, callback);
1014                                 }
1015                         });
1016         }
1017         else  if (callback != null) {
1018             callback.execute();
1019         }
1020     }
1021
1022     public void copyFolder(final Folder f, final String targetUsername, final String targetUri, final Command callback) {
1023         String path = targetUri + "/" + f.getName();
1024         PutRequest createFolder = new PutRequest(getApiPath(), targetUsername, path) {
1025             @Override
1026             public void onSuccess(Resource result) {
1027                 GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, getApiPath(), f.getOwner(), "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + URL.encodeQueryString(f.getPrefix()), f) {
1028
1029                                         @Override
1030                                         public void onSuccess(final Folder _f) {
1031                                 Iterator<File> iter = _f.getFiles().iterator();
1032                                 copyFiles(iter, targetUsername, targetUri + "/" + _f.getName(), new Command() {
1033                                     @Override
1034                                     public void execute() {
1035                                         Iterator<Folder> iterf = _f.getSubfolders().iterator();
1036                                         copySubfolders(iterf, targetUsername, targetUri + "/" + _f.getName(), callback);
1037                                     }
1038                                 });
1039                                         }
1040
1041                                         @Override
1042                                         public void onError(Throwable t) {
1043                                 GWT.log("", t);
1044                                                 setError(t);
1045                                 if (t instanceof RestException) {
1046                                     displayError("Unable to get folder: " + ((RestException) t).getHttpStatusText());
1047                                 }
1048                                 else
1049                                     displayError("System error getting folder: " + t.getMessage());
1050                                         }
1051
1052                                         @Override
1053                                         protected void onUnauthorized(Response response) {
1054                                                 sessionExpired();
1055                                         }
1056                                 };
1057                                 getFolder.setHeader("X-Auth-Token", getToken());
1058                                 Scheduler.get().scheduleDeferred(getFolder);
1059             }
1060
1061             @Override
1062             public void onError(Throwable t) {
1063                 GWT.log("", t);
1064                                 setError(t);
1065                if (t instanceof RestException) {
1066                     displayError("Unable to create folder: " + ((RestException) t).getHttpStatusText());
1067                 }
1068                 else
1069                     displayError("System error creating folder: " + t.getMessage());
1070             }
1071
1072                         @Override
1073                         protected void onUnauthorized(Response response) {
1074                                 sessionExpired();
1075                         }
1076         };
1077         createFolder.setHeader("X-Auth-Token", getToken());
1078         createFolder.setHeader("Accept", "*/*");
1079         createFolder.setHeader("Content-Length", "0");
1080         createFolder.setHeader("Content-Type", "application/folder");
1081         Scheduler.get().scheduleDeferred(createFolder);
1082     }
1083     
1084     public void addSelectionModel(@SuppressWarnings("rawtypes") SingleSelectionModel model) {
1085         selectionModels.add(model);
1086     }
1087
1088         public OtherSharedTreeView getOtherSharedTreeView() {
1089                 return otherSharedTreeView;
1090         }
1091
1092         public void updateTrash(boolean showFiles, Command callback) {
1093                 updateFolder(trash, showFiles, callback, true);
1094         }
1095
1096         public void updateGroupsNode() {
1097                 groupTreeView.updateGroupNode(null);
1098         }
1099
1100         public Group addGroup(String groupname) {
1101                 Group newGroup = new Group(groupname);
1102                 account.addGroup(newGroup);
1103                 groupTreeView.updateGroupNode(null);
1104                 return newGroup;
1105         }
1106
1107         public void removeGroup(Group group) {
1108                 account.removeGroup(group);
1109                 updateGroupsNode();
1110         }
1111
1112         public TreeView getSelectedTree() {
1113                 return selectedTree;
1114         }
1115         
1116         public void setSelectedTree(TreeView selected) {
1117                 selectedTree = selected;
1118         }
1119
1120         public Folder getSelection() {
1121                 if (selectedTree != null)
1122                         return selectedTree.getSelection();
1123                 return null;
1124         }
1125
1126         public void showFolderStatistics(int folderFileCount) {
1127                 numOfFiles.setHTML(String.valueOf(folderFileCount));
1128         }
1129
1130         public GroupTreeView getGroupTreeView() {
1131                 return groupTreeView;
1132         }
1133
1134         public void sessionExpired() {
1135                 new SessionExpiredDialog(this).center();
1136         }
1137
1138         public void updateRootFolder(Command callback) {
1139                 updateFolder(account.getPithos(), false, callback, true);
1140         }
1141
1142         void createMySharedTree() {
1143                 mysharedTreeSelectionModel = new SingleSelectionModel<Folder>();
1144                 mysharedTreeSelectionModel.addSelectionChangeHandler(new Handler() {
1145                     @Override
1146                     public void onSelectionChange(SelectionChangeEvent event) {
1147                         if (mysharedTreeSelectionModel.getSelectedObject() != null) {
1148                             deselectOthers(mysharedTreeView, mysharedTreeSelectionModel);
1149                             upload.setEnabled(false);
1150                             disableUploadArea();
1151                             updateSharedFolder(mysharedTreeSelectionModel.getSelectedObject(), true);
1152                                         showRelevantToolbarButtons();
1153                         }
1154                                 else {
1155                                         if (getSelectedTree().equals(mysharedTreeView))
1156                                                 setSelectedTree(null);
1157                                         if (getSelectedTree() == null)
1158                                                 showRelevantToolbarButtons();
1159                                 }
1160                     }
1161                 });
1162                 selectionModels.add(mysharedTreeSelectionModel);
1163                 mysharedTreeViewModel = new MysharedTreeViewModel(Pithos.this, mysharedTreeSelectionModel);
1164                 mysharedTreeViewModel.initialize(new Command() {
1165                         
1166                         @Override
1167                         public void execute() {
1168                             mysharedTreeView = new MysharedTreeView(mysharedTreeViewModel);
1169                                 trees.insert(mysharedTreeView, 2);
1170                                 treeViews.add(mysharedTreeView);
1171                                 createOtherSharedTree();
1172                         }
1173                 });
1174         }
1175
1176         void createOtherSharedTree() {
1177                 otherSharedTreeSelectionModel = new SingleSelectionModel<Folder>();
1178                 otherSharedTreeSelectionModel.addSelectionChangeHandler(new Handler() {
1179                     @Override
1180                     public void onSelectionChange(SelectionChangeEvent event) {
1181                         if (otherSharedTreeSelectionModel.getSelectedObject() != null) {
1182                             deselectOthers(otherSharedTreeView, otherSharedTreeSelectionModel);
1183                             applyPermissions(otherSharedTreeSelectionModel.getSelectedObject());
1184                             updateOtherSharedFolder(otherSharedTreeSelectionModel.getSelectedObject(), true, null);
1185                                         showRelevantToolbarButtons();
1186                         }
1187                                 else {
1188                                         if (getSelectedTree().equals(otherSharedTreeView))
1189                                                 setSelectedTree(null);
1190                                         if (getSelectedTree() == null)
1191                                                 showRelevantToolbarButtons();
1192                                 }
1193                     }
1194                 });
1195                 selectionModels.add(otherSharedTreeSelectionModel);
1196                 otherSharedTreeViewModel = new OtherSharedTreeViewModel(Pithos.this, otherSharedTreeSelectionModel);
1197                 otherSharedTreeViewModel.initialize(new Command() {
1198                         
1199                         @Override
1200                         public void execute() {
1201                             otherSharedTreeView = new OtherSharedTreeView(otherSharedTreeViewModel);
1202                                 trees.insert(otherSharedTreeView, 1);
1203                                 treeViews.add(otherSharedTreeView);
1204                         }
1205                 });
1206         }
1207
1208         public native void log1(String message)/*-{
1209                 $wnd.console.log(message);
1210         }-*/;
1211
1212         public String getErrorData() {
1213                 if (error != null)
1214                         return error.toString();
1215                 return "";
1216         }
1217         
1218         public void setError(Throwable t) {
1219                 error = t;
1220         }
1221         
1222         public void showRelevantToolbarButtons() {
1223                 toolbar.showRelevantButtons();
1224         }
1225
1226         public FileUploadDialog getFileUploadDialog() {
1227                 if (fileUploadDialog == null)
1228                         fileUploadDialog = new FileUploadDialog(this);
1229                 return fileUploadDialog;
1230         }
1231
1232         public void hideUploadIndicator() {
1233                 upload.removeStyleName("pithos-uploadButton-loading");
1234                 upload.setTitle("");
1235         }
1236         
1237         public void showUploadIndicator() {
1238                 upload.addStyleName("pithos-uploadButton-loading");
1239                 upload.setTitle("Upload in progress. Click for details.");
1240         }
1241
1242         public void scheduleFolderHeadCommand(final Folder folder, final Command callback) {
1243                 if (folder == null) {
1244                         if (callback != null)
1245                                 callback.execute();
1246                 }
1247                 else {
1248                         HeadRequest<Folder> headFolder = new HeadRequest<Folder>(Folder.class, getApiPath(), folder.getOwner(), folder.getUri(), folder) {
1249         
1250                                 @Override
1251                                 public void onSuccess(Folder _result) {
1252                                         if (callback != null)
1253                                                 callback.execute();
1254                                 }
1255         
1256                                 @Override
1257                                 public void onError(Throwable t) {
1258                                 if (t instanceof RestException) {
1259                                         if (((RestException) t).getHttpStatusCode() == Response.SC_NOT_FOUND) {
1260                                 final String path = folder.getUri();
1261                                 PutRequest newFolder = new PutRequest(getApiPath(), folder.getOwner(), path) {
1262                                     @Override
1263                                     public void onSuccess(Resource _result) {
1264                                         scheduleFolderHeadCommand(folder, callback);
1265                                     }
1266         
1267                                     @Override
1268                                     public void onError(Throwable _t) {
1269                                         GWT.log("", _t);
1270                                                                 setError(_t);
1271                                         if(_t instanceof RestException){
1272                                             displayError("Unable to create folder: " + ((RestException) _t).getHttpStatusText());
1273                                         }
1274                                         else
1275                                             displayError("System error creating folder: " + _t.getMessage());
1276                                     }
1277         
1278                                                 @Override
1279                                                 protected void onUnauthorized(Response response) {
1280                                                         sessionExpired();
1281                                                 }
1282                                 };
1283                                 newFolder.setHeader("X-Auth-Token", getToken());
1284                                 newFolder.setHeader("Content-Type", "application/folder");
1285                                 newFolder.setHeader("Accept", "*/*");
1286                                 newFolder.setHeader("Content-Length", "0");
1287                                 Scheduler.get().scheduleDeferred(newFolder);
1288                                         }
1289                                         else
1290                                                 displayError("Error heading folder: " + ((RestException) t).getHttpStatusText());
1291                                 }
1292                                 else
1293                                     displayError("System error heading folder: " + t.getMessage());
1294         
1295                                 GWT.log("Error heading folder", t);
1296                                         setError(t);
1297                                 }
1298         
1299                                 @Override
1300                                 protected void onUnauthorized(Response response) {
1301                                         sessionExpired();
1302                                 }
1303                         };
1304                         headFolder.setHeader("X-Auth-Token", getToken());
1305                         Scheduler.get().scheduleDeferred(headFolder);
1306                 }
1307         }
1308
1309         public void scheduleFileHeadCommand(File f, final Command callback) {
1310                 HeadRequest<File> headFile = new HeadRequest<File>(File.class, getApiPath(), f.getOwner(), f.getUri(), f) {
1311
1312                         @Override
1313                         public void onSuccess(File _result) {
1314                                 if (callback != null)
1315                                         callback.execute();
1316                         }
1317
1318                         @Override
1319                         public void onError(Throwable t) {
1320                         GWT.log("Error heading file", t);
1321                                 setError(t);
1322                         if (t instanceof RestException)
1323                             displayError("Error heading file: " + ((RestException) t).getHttpStatusText());
1324                         else
1325                             displayError("System error heading file: " + t.getMessage());
1326                         }
1327
1328                         @Override
1329                         protected void onUnauthorized(Response response) {
1330                                 sessionExpired();
1331                         }
1332                 };
1333                 headFile.setHeader("X-Auth-Token", getToken());
1334                 Scheduler.get().scheduleDeferred(headFile);
1335         }
1336
1337         public boolean isMySharedSelected() {
1338                 return getSelectedTree().equals(getMySharedTreeView());
1339         }
1340         
1341         private Folder getUploadFolder() {
1342                 if (folderTreeView.equals(getSelectedTree()) || otherSharedTreeView.equals(getSelectedTree())) {
1343                         return getSelection();
1344                 }
1345                 return null;
1346         }
1347         
1348         private void updateUploadFolder() {
1349                 updateUploadFolder(null);
1350         }
1351         
1352         private void updateUploadFolder(final JsArrayString urls) {
1353                 if (folderTreeView.equals(getSelectedTree()) || otherSharedTreeView.equals(getSelectedTree())) {
1354                         Folder f = getSelection();
1355                         if (getSelectedTree().equals(getFolderTreeView()))
1356                                 updateFolder(f, true, new Command() {
1357                                 
1358                                         @Override
1359                                         public void execute() {
1360                                                 updateStatistics();
1361                                                 if (urls != null)
1362                                                         selectUploadedFiles(urls);
1363                                         }
1364                                 }, false);
1365                         else
1366                                 updateOtherSharedFolder(f, true, null);
1367                 }
1368         }
1369
1370         public native void disableUploadArea() /*-{
1371                 var uploader = $wnd.$("#uploader").pluploadQueue();
1372                 var dropElm = $wnd.document.getElementById('rightPanel');
1373                 $wnd.plupload.removeAllEvents(dropElm, uploader.id);
1374         }-*/;
1375
1376         public native void enableUploadArea() /*-{
1377                 var uploader = $wnd.$("#uploader").pluploadQueue();
1378                 var dropElm = $wnd.document.getElementById('rightPanel');
1379                 $wnd.plupload.removeAllEvents(dropElm, uploader.id);
1380                 if (uploader.runtime == 'html5') {
1381                         uploader.settings.drop_element = 'rightPanel';
1382                         uploader.trigger('PostInit');
1383                 }
1384         }-*/;
1385         
1386         public void showUploadAlert(int numOfFiles) {
1387                 uploadAlert = new UploadAlert(this, numOfFiles);
1388                 uploadAlert.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
1389                         
1390                         @Override
1391                         public void setPosition(int offsetWidth, int offsetHeight) {
1392                                 uploadAlert.setPopupPosition((Window.getClientWidth() - offsetWidth)/2, Window.getClientHeight() - offsetHeight);
1393                         }
1394                 });
1395         }
1396         
1397         public void hideUploadAlert() {
1398                 uploadAlert.hide();
1399         }
1400         
1401         public void selectUploadedFiles(JsArrayString urls) {
1402                 List<String> selectedUrls = new ArrayList<String>();
1403                 for (int i=0; i<urls.length(); i++)
1404                         selectedUrls.add(urls.get(i));
1405                 fileList.selectByUrl(selectedUrls);
1406         }
1407 }