First implementation of public permission setting
[pithos] / web_client / src / gr / grnet / pithos / web / client / Pithos.java
1 /*
2  * Copyright 2011 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 com.google.gwt.core.client.Scheduler;
38 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
39 import com.google.gwt.http.client.Request;
40 import com.google.gwt.http.client.RequestBuilder;
41 import com.google.gwt.http.client.RequestCallback;
42 import com.google.gwt.http.client.RequestException;
43 import com.google.gwt.http.client.Response;
44 import com.google.gwt.json.client.JSONArray;
45 import com.google.gwt.json.client.JSONObject;
46 import com.google.gwt.json.client.JSONParser;
47 import com.google.gwt.json.client.JSONString;
48 import com.google.gwt.json.client.JSONValue;
49 import com.google.gwt.user.client.Command;
50 import com.google.gwt.view.client.SelectionChangeEvent;
51 import com.google.gwt.view.client.SelectionChangeEvent.Handler;
52 import com.google.gwt.view.client.SingleSelectionModel;
53 import gr.grnet.pithos.web.client.commands.GetUserCommand;
54 import gr.grnet.pithos.web.client.foldertree.AccountResource;
55 import gr.grnet.pithos.web.client.foldertree.File;
56 import gr.grnet.pithos.web.client.foldertree.Folder;
57 import gr.grnet.pithos.web.client.foldertree.FolderTreeView;
58 import gr.grnet.pithos.web.client.foldertree.FolderTreeViewModel;
59 import gr.grnet.pithos.web.client.foldertree.Resource;
60 import gr.grnet.pithos.web.client.rest.DeleteRequest;
61 import gr.grnet.pithos.web.client.rest.GetRequest;
62 import gr.grnet.pithos.web.client.rest.PutRequest;
63 import gr.grnet.pithos.web.client.rest.RestException;
64 import gr.grnet.pithos.web.client.rest.resource.FileResource;
65 import gr.grnet.pithos.web.client.rest.resource.OtherUserResource;
66 import gr.grnet.pithos.web.client.rest.resource.RestResource;
67 import gr.grnet.pithos.web.client.rest.resource.RestResourceWrapper;
68 import gr.grnet.pithos.web.client.rest.resource.SharedResource;
69 import gr.grnet.pithos.web.client.rest.resource.TrashResource;
70 import gr.grnet.pithos.web.client.rest.resource.UserResource;
71
72 import gr.grnet.pithos.web.client.tagtree.Tag;
73 import gr.grnet.pithos.web.client.tagtree.TagTreeView;
74 import gr.grnet.pithos.web.client.tagtree.TagTreeViewModel;
75 import java.util.ArrayList;
76 import java.util.Arrays;
77 import java.util.Collection;
78 import java.util.Date;
79 import java.util.HashMap;
80 import java.util.Iterator;
81 import java.util.List;
82
83 import com.google.gwt.core.client.EntryPoint;
84 import com.google.gwt.core.client.GWT;
85 import com.google.gwt.event.logical.shared.ResizeEvent;
86 import com.google.gwt.event.logical.shared.ResizeHandler;
87 import com.google.gwt.event.logical.shared.SelectionEvent;
88 import com.google.gwt.event.logical.shared.SelectionHandler;
89 import com.google.gwt.http.client.URL;
90 import com.google.gwt.i18n.client.DateTimeFormat;
91 import com.google.gwt.resources.client.ClientBundle;
92 import com.google.gwt.resources.client.ImageResource;
93 import com.google.gwt.user.client.Cookies;
94 import com.google.gwt.user.client.Event;
95 import com.google.gwt.user.client.History;
96 import com.google.gwt.user.client.Window;
97 import com.google.gwt.user.client.ui.AbstractImagePrototype;
98 import com.google.gwt.user.client.ui.DecoratedTabPanel;
99 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
100 import com.google.gwt.user.client.ui.HorizontalSplitPanel;
101 import com.google.gwt.user.client.ui.RootPanel;
102 import com.google.gwt.user.client.ui.TabPanel;
103 import com.google.gwt.user.client.ui.VerticalPanel;
104 import java.util.Set;
105
106 /**
107  * Entry point classes define <code>onModuleLoad()</code>.
108  */
109 public class Pithos implements EntryPoint, ResizeHandler {
110
111         /**
112          * A constant that denotes the completion of an IncrementalCommand.
113          */
114         public static final boolean DONE = false;
115
116         public static final int VISIBLE_FILE_COUNT = 25;
117
118         /**
119          * Instantiate an application-level image bundle. This object will provide
120          * programmatic access to all the images needed by widgets.
121          */
122         private static Images images = (Images) GWT.create(Images.class);
123
124     public String getUsername() {
125         return username;
126     }
127
128     public void setAccount(AccountResource acct) {
129         account = acct;
130     }
131
132     public AccountResource getAccount() {
133         return account;
134     }
135
136     public void updateFolder(Folder f) {
137         folderTreeView.updateFolder(f);
138     }
139
140     public void updateTag(Tag t) {
141         tagTreeView.updateTag(t);
142     }
143
144     public void updateTags() {
145         tagTreeViewModel.initialize(getAllTags());
146     }
147
148     public List<Tag> getAllTags() {
149         List<Tag> tagList = new ArrayList<Tag>();
150         for (Folder f : account.getContainers()) {
151             for (String t : f.getTags()) {
152                 tagList.add(new Tag(t));
153             }
154         }
155         return tagList;
156     }
157
158     /**
159          * An aggregate image bundle that pulls together all the images for this
160          * application into a single bundle.
161          */
162         public interface Images extends ClientBundle, TopPanel.Images, StatusPanel.Images, FileMenu.Images, EditMenu.Images, SettingsMenu.Images, FilePropertiesDialog.Images, MessagePanel.Images, FileList.Images, Search.Images, CellTreeView.Images {
163
164                 @Source("gr/grnet/pithos/resources/document.png")
165                 ImageResource folders();
166
167                 @Source("gr/grnet/pithos/resources/edit_group_22.png")
168                 ImageResource groups();
169
170                 @Source("gr/grnet/pithos/resources/search.png")
171                 ImageResource search();
172         }
173
174         /**
175          * The single Pithos instance.
176          */
177         private static Pithos singleton;
178
179         /**
180          * Gets the singleton Pithos instance.
181          *
182          * @return the Pithos object
183          */
184         public static Pithos get() {
185                 if (Pithos.singleton == null)
186                         Pithos.singleton = new Pithos();
187                 return Pithos.singleton;
188         }
189
190         /**
191          * The Application Clipboard implementation;
192          */
193         private Clipboard clipboard = new Clipboard();
194
195         private UserResource currentUserResource;
196
197         /**
198          * The top panel that contains the menu bar.
199          */
200         private TopPanel topPanel;
201
202         /**
203          * The panel that contains the various system messages.
204          */
205         private MessagePanel messagePanel = new MessagePanel(Pithos.images);
206
207         /**
208          * The bottom panel that contains the status bar.
209          */
210         private StatusPanel statusPanel = null;
211
212         /**
213          * The top right panel that displays the logged in user details
214          */
215         private UserDetailsPanel userDetailsPanel = new UserDetailsPanel();
216
217         /**
218          * The file list widget.
219          */
220         private FileList fileList;
221
222         /**
223          * The tab panel that occupies the right side of the screen.
224          */
225         private TabPanel inner = new DecoratedTabPanel(){
226                 
227 //              public void onBrowserEvent(com.google.gwt.user.client.Event event) {
228 //                      if (DOM.eventGetType(event) == Event.ONCONTEXTMENU){
229 //                              if(isFileListShowing()){
230 //                                      getFileList().showContextMenu(event);
231 //                              }
232 //                      }
233 //              };
234         };
235
236
237         /**
238          * The split panel that will contain the left and right panels.
239          */
240         private HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
241
242         /**
243          * The widget that displays the tree of folders.
244          */
245         
246         private CellTreeView treeView = null;
247         /**
248          * The currently selected item in the application, for use by the Edit menu
249          * commands. Potential types are Folder, File, User and Group.
250          */
251         private Object currentSelection;
252
253
254         /**
255          * The WebDAV password of the current user
256          */
257         private String webDAVPassword;
258
259         public HashMap<String, String> userFullNameMap = new HashMap<String, String>();
260
261     private String username = null;
262
263     /**
264      * The authentication token of the current user.
265      */
266     private String token;
267
268     private SingleSelectionModel<Folder> folderTreeSelectionModel;
269     private FolderTreeViewModel folderTreeViewModel;
270     private FolderTreeView folderTreeView;
271
272     private SingleSelectionModel<Tag> tagTreeSelectionModel;
273     private TagTreeViewModel tagTreeViewModel;
274     private TagTreeView tagTreeView;
275
276     private AccountResource account;
277
278         @Override
279         public void onModuleLoad() {
280                 // Initialize the singleton before calling the constructors of the
281                 // various widgets that might call Pithos.get().
282                 singleton = this;
283                 if (parseUserCredentials())
284             initialize();
285         }
286
287     private void initialize() {
288         topPanel = new TopPanel(Pithos.images);
289         topPanel.setWidth("100%");
290
291         messagePanel.setWidth("100%");
292         messagePanel.setVisible(false);
293
294
295         // Inner contains the various lists.
296         inner.sinkEvents(Event.ONCONTEXTMENU);
297         inner.setAnimationEnabled(true);
298         inner.getTabBar().addStyleName("pithos-MainTabBar");
299         inner.getDeckPanel().addStyleName("pithos-MainTabPanelBottom");
300
301         inner.setWidth("100%");
302
303         inner.addSelectionHandler(new SelectionHandler<Integer>() {
304
305             @Override
306             public void onSelection(SelectionEvent<Integer> event) {
307                 int tabIndex = event.getSelectedItem();
308                 switch (tabIndex) {
309                     case 0:
310                         fileList.updateCurrentlyShowingStats();
311                         break;
312                 }
313             }
314         });
315
316         folderTreeSelectionModel = new SingleSelectionModel<Folder>();
317         folderTreeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
318             @Override
319             public void onSelectionChange(SelectionChangeEvent event) {
320                 if (folderTreeSelectionModel.getSelectedObject() != null) {
321                     tagTreeSelectionModel.setSelected(tagTreeSelectionModel.getSelectedObject(), false);
322                     Folder f = folderTreeSelectionModel.getSelectedObject();
323                     updateFolder(f);
324                 }
325             }
326         });
327
328         folderTreeViewModel = new FolderTreeViewModel(folderTreeSelectionModel);
329         folderTreeView = new FolderTreeView(folderTreeViewModel);
330
331         fileList = new FileList(images, folderTreeView);
332         inner.add(fileList, createHeaderHTML(AbstractImagePrototype.create(images.folders()), "Files"), true);
333
334         tagTreeSelectionModel = new SingleSelectionModel<Tag>();
335         tagTreeSelectionModel.addSelectionChangeHandler(new Handler() {
336             @Override
337             public void onSelectionChange(SelectionChangeEvent event) {
338                 if (tagTreeSelectionModel.getSelectedObject() != null) {
339                     folderTreeSelectionModel.setSelected(folderTreeSelectionModel.getSelectedObject(), false);
340                     Tag t = tagTreeSelectionModel.getSelectedObject();
341                     updateTag(t);
342                 }
343             }
344         });
345         tagTreeViewModel = new TagTreeViewModel(tagTreeSelectionModel);
346         tagTreeView = new TagTreeView(tagTreeViewModel);
347
348         VerticalPanel trees = new VerticalPanel();
349         trees.add(folderTreeView);
350         trees.add(tagTreeView);
351         // Add the left and right panels to the split panel.
352         splitPanel.setLeftWidget(trees);
353         splitPanel.setRightWidget(inner);
354         splitPanel.setSplitPosition("25%");
355         splitPanel.setSize("100%", "100%");
356         splitPanel.addStyleName("pithos-splitPanel");
357
358         // Create a dock panel that will contain the menu bar at the top,
359         // the shortcuts to the left, the status bar at the bottom and the
360         // right panel taking the rest.
361         VerticalPanel outer = new VerticalPanel();
362         outer.add(topPanel);
363         outer.add(messagePanel);
364         outer.add(splitPanel);
365         statusPanel = new StatusPanel(Pithos.images);
366         outer.add(statusPanel);
367         outer.setWidth("100%");
368         outer.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER);
369
370         outer.setSpacing(4);
371
372         // Hook the window resize event, so that we can adjust the UI.
373         Window.addResizeHandler(this);
374         // Clear out the window's built-in margin, because we want to take
375         // advantage of the entire client area.
376         Window.setMargin("0px");
377         // Finally, add the outer panel to the RootPanel, so that it will be
378         // displayed.
379         RootPanel.get().add(outer);
380         // Call the window resized handler to get the initial sizes setup. Doing
381         // this in a deferred command causes it to occur after all widgets'
382         // sizes have been computed by the browser.
383         Scheduler.get().scheduleDeferred(new ScheduledCommand() {
384
385             @Override
386             public void execute() {
387                 onWindowResized(Window.getClientHeight());
388             }
389         });
390
391         Scheduler.get().scheduleDeferred(new ScheduledCommand() {
392             @Override
393             public void execute() {
394                 fetchAccount();
395             }
396         });
397     }
398
399     public void showFiles(Folder f) {
400         inner.selectTab(0);
401         if (f.isTrash()) {
402             fileList.showTrash();
403         }
404         else
405             fileList.showFiles();
406         Set<File> files = f.getFiles();
407         showFiles(files);
408     }
409
410     public void showFiles(Set<File> files) {
411         //Iterator<File> iter = files.iterator();
412         //fetchFile(iter, files);
413         fileList.setFiles(new ArrayList<File>(files));
414     }
415
416     private void fetchFile(final Iterator<File> iter, final Set<File> files) {
417         if (iter.hasNext()) {
418             File file = iter.next();
419             String path = file.getUri() + "?format=json";
420             GetRequest<File> getFile = new GetRequest<File>(File.class, getApiPath(), username, path, file) {
421                 @Override
422                 public void onSuccess(File result) {
423                     fetchFile(iter, files);
424                 }
425
426                 @Override
427                 public void onError(Throwable t) {
428                     GWT.log("Error getting file", t);
429                     if (t instanceof RestException)
430                         Pithos.get().displayError("Error getting file: " + ((RestException) t).getHttpStatusText());
431                     else
432                         Pithos.get().displayError("System error fetching file: " + t.getMessage());
433                 }
434             };
435             getFile.setHeader("X-Auth-Token", "0000");
436             Scheduler.get().scheduleDeferred(getFile);
437         }
438         else
439             fileList.setFiles(new ArrayList<File>(files));
440     }
441
442     /**
443          * Parse and store the user credentials to the appropriate fields.
444          */
445         private boolean parseUserCredentials() {
446                 Configuration conf = (Configuration) GWT.create(Configuration.class);
447                 String cookie = conf.authCookie();
448                 String auth = Cookies.getCookie(cookie);
449                 if (auth == null) {
450                         authenticateUser();
451             return false;
452         }
453         else {
454             String[] authSplit = auth.split("\\" + conf.cookieSeparator(), 2);
455             if (authSplit.length != 2) {
456                 authenticateUser();
457                 return false;
458             }
459             else {
460                 username = authSplit[0];
461                 token = authSplit[1];
462                 return true;
463             }
464         }
465         }
466
467     /**
468          * Redirect the user to the login page for authentication.
469          */
470         protected void authenticateUser() {
471                 Configuration conf = (Configuration) GWT.create(Configuration.class);
472
473 //        Window.Location.assign(GWT.getModuleBaseURL() + conf.loginUrl() + "?next=" + Window.Location.getHref());
474         Cookies.setCookie(conf.authCookie(), "test" + conf.cookieSeparator() + "0000");
475         Window.Location.assign(GWT.getModuleBaseURL() + "pithos.html");
476         }
477
478     private void fetchAccount() {
479         String path = "?format=json";
480
481         GetRequest<AccountResource> getAccount = new GetRequest<AccountResource>(AccountResource.class, getApiPath(), username, path) {
482             @Override
483             public void onSuccess(AccountResource result) {
484                 account = result;
485                 statusPanel.displayStats(account);
486                 inner.selectTab(0);
487                 if (account.getContainers().isEmpty())
488                     createHomeContainers();
489                 else
490                     folderTreeViewModel.initialize(account);
491             }
492
493             @Override
494             public void onError(Throwable t) {
495                 GWT.log("Error getting account", t);
496                 if (t instanceof RestException)
497                     Pithos.get().displayError("Error getting account: " + ((RestException) t).getHttpStatusText());
498                 else
499                     Pithos.get().displayError("System error fetching user data: " + t.getMessage());
500             }
501         };
502         getAccount.setHeader("X-Auth-Token", token);
503         Scheduler.get().scheduleDeferred(getAccount);
504     }
505
506     private void createHomeContainers() {
507         String path = "/pithos";
508         PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
509             @Override
510             public void onSuccess(Resource result) {
511                 fetchAccount();
512             }
513
514             @Override
515             public void onError(Throwable t) {
516                 GWT.log("Error creating pithos", t);
517                 if (t instanceof RestException)
518                     Pithos.get().displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText());
519                 else
520                     Pithos.get().displayError("System error Error creating pithos: " + t.getMessage());
521             }
522         };
523         createPithos.setHeader("X-Auth-Token", getToken());
524         Scheduler.get().scheduleDeferred(createPithos);
525     }
526
527         /**
528          * Clear the cookie and redirect the user to the logout page.
529          */
530         void logout() {
531                 Configuration conf = (Configuration) GWT.create(Configuration.class);
532                 String cookie = conf.authCookie();
533                 String domain = Window.Location.getHostName();
534                 String path = Window.Location.getPath();
535                 Cookies.setCookie(cookie, "", null, domain, path, false);
536         String baseUrl = GWT.getModuleBaseURL();
537         String homeUrl = baseUrl.substring(0, baseUrl.indexOf(path));
538                 Window.Location.assign(homeUrl + conf.logoutUrl());
539         }
540
541         /**
542          * Creates an HTML fragment that places an image & caption together, for use
543          * in a group header.
544          *
545          * @param imageProto an image prototype for an image
546          * @param caption the group caption
547          * @return the header HTML fragment
548          */
549         private String createHeaderHTML(AbstractImagePrototype imageProto, String caption) {
550                 String captionHTML = "<table class='caption' cellpadding='0' " 
551                 + "cellspacing='0'>" + "<tr><td class='lcaption'>" + imageProto.getHTML() 
552                 + "</td><td id =" + caption +" class='rcaption'><b style='white-space:nowrap'>&nbsp;" 
553                 + caption + "</b></td></tr></table>";
554                 return captionHTML;
555         }
556
557         private void onWindowResized(int height) {
558                 // Adjust the split panel to take up the available room in the window.
559                 int newHeight = height - splitPanel.getAbsoluteTop() - 44;
560                 if (newHeight < 1)
561                         newHeight = 1;
562                 splitPanel.setHeight("" + newHeight);
563                 inner.setHeight("" + newHeight);
564         }
565
566         @Override
567         public void onResize(ResizeEvent event) {
568                 int height = event.getHeight();
569                 onWindowResized(height);
570         }
571
572         public boolean isFileListShowing() {
573                 int tab = inner.getTabBar().getSelectedTab();
574                 if (tab == 0)
575                         return true;
576                 return false;
577         }
578
579         public boolean isSearchResultsShowing() {
580                 int tab = inner.getTabBar().getSelectedTab();
581                 if (tab == 2)
582                         return true;
583                 return false;
584         }
585
586         /**
587          * Make the file list visible.
588          *
589          * @param update
590          */
591         public void showFileList(boolean update) {
592                 if(update){
593                         getTreeView().refreshCurrentNode(true);
594                 }
595                 else{
596                         RestResource currentFolder = getTreeView().getSelection();
597                         if(currentFolder!=null){
598                                 showFileList(currentFolder);
599                 }
600                 }
601
602         }
603         
604         public void showFileList(RestResource r) {
605                 showFileList(r,true);
606         }
607         
608         public void showFileList(RestResource r, boolean clearSelection) {
609                 RestResource currentFolder = r;
610                 if(currentFolder!=null){
611                         List<FileResource> files = null;
612                         if (currentFolder instanceof RestResourceWrapper) {
613                                 RestResourceWrapper folder = (RestResourceWrapper) currentFolder;
614                                 files = folder.getResource().getFiles();
615                         }
616                 }
617                 inner.selectTab(0);
618         }
619
620         /**
621          * Display the 'loading' indicator.
622          */
623         public void showLoadingIndicator(String message, String path) {
624                 if(path!=null){
625                         String[] split = path.split("/");
626                         message = message +" "+URL.decode(split[split.length-1]);
627                 }
628                 topPanel.getLoading().show(message);
629         }
630
631         /**
632          * Hide the 'loading' indicator.
633          */
634         public void hideLoadingIndicator() {
635                 topPanel.getLoading().hide();
636         }
637
638         /**
639          * A native JavaScript method to reach out to the browser's window and
640          * invoke its resizeTo() method.
641          *
642          * @param x the new width
643          * @param y the new height
644          */
645         public static native void resizeTo(int x, int y) /*-{
646                 $wnd.resizeTo(x,y);
647         }-*/;
648
649         /**
650          * A helper method that returns true if the user's list is currently visible
651          * and false if it is hidden.
652          *
653          * @return true if the user list is visible
654          */
655         public boolean isUserListVisible() {
656                 return inner.getTabBar().getSelectedTab() == 1;
657         }
658
659         /**
660          * Display an error message.
661          *
662          * @param msg the message to display
663          */
664         public void displayError(String msg) {
665                 messagePanel.displayError(msg);
666         }
667
668         /**
669          * Display a warning message.
670          *
671          * @param msg the message to display
672          */
673         public void displayWarning(String msg) {
674                 messagePanel.displayWarning(msg);
675         }
676
677         /**
678          * Display an informational message.
679          *
680          * @param msg the message to display
681          */
682         public void displayInformation(String msg) {
683                 messagePanel.displayInformation(msg);
684         }
685
686         /**
687          * Retrieve the folders.
688          *
689          * @return the folders
690          
691         public Folders getFolders() {
692                 return folders;
693         }*/
694
695         /**
696          * Retrieve the currentSelection.
697          *
698          * @return the currentSelection
699          */
700         public Object getCurrentSelection() {
701                 return currentSelection;
702         }
703
704         /**
705          * Modify the currentSelection.
706          *
707          * @param newCurrentSelection the currentSelection to set
708          */
709         public void setCurrentSelection(Object newCurrentSelection) {
710                 currentSelection = newCurrentSelection;
711         }
712
713         /**
714          * Retrieve the fileList.
715          *
716          * @return the fileList
717          */
718         public FileList getFileList() {
719                 return fileList;
720         }
721
722         /**
723          * Retrieve the topPanel.
724          *
725          * @return the topPanel
726          */
727         TopPanel getTopPanel() {
728                 return topPanel;
729         }
730
731         /**
732          * Retrieve the clipboard.
733          *
734          * @return the clipboard
735          */
736         public Clipboard getClipboard() {
737                 return clipboard;
738         }
739
740         public StatusPanel getStatusPanel() {
741                 return statusPanel;
742         }
743
744         /**
745          * Retrieve the userDetailsPanel.
746          *
747          * @return the userDetailsPanel
748          */
749         public UserDetailsPanel getUserDetailsPanel() {
750                 return userDetailsPanel;
751         }
752
753         
754
755         public String getToken() {
756                 return token;
757         }
758
759         public String getWebDAVPassword() {
760                 return webDAVPassword;
761         }
762
763         /**
764          * Retrieve the currentUserResource.
765          *
766          * @return the currentUserResource
767          */
768         public UserResource getCurrentUserResource() {
769                 return currentUserResource;
770         }
771
772         /**
773          * Modify the currentUserResource.
774          *
775          * @param newUser the new currentUserResource
776          */
777         public void setCurrentUserResource(UserResource newUser) {
778                 currentUserResource = newUser;
779         }
780
781         public static native void preventIESelection() /*-{
782                 $doc.body.onselectstart = function () { return false; };
783         }-*/;
784
785         public static native void enableIESelection() /*-{
786                 if ($doc.body.onselectstart != null)
787                 $doc.body.onselectstart = null;
788         }-*/;
789
790         /**
791          * @return the absolute path of the API root URL
792          */
793         public String getApiPath() {
794                 Configuration conf = (Configuration) GWT.create(Configuration.class);
795                 return conf.apiPath();
796         }
797
798         /**
799          * Convert server date to local time according to browser timezone
800          * and format it according to localized pattern.
801          * Time is always formatted to 24hr format.
802          * NB: This assumes that server runs in UTC timezone. Otherwise
803          * we would need to adjust for server time offset as well.
804          *
805          * @param date
806          * @return String
807          */
808         public static String formatLocalDateTime(Date date) {
809                 Date convertedDate = new Date(date.getTime() - date.getTimezoneOffset());
810                 final DateTimeFormat dateFormatter = DateTimeFormat.getShortDateFormat();
811                 final DateTimeFormat timeFormatter = DateTimeFormat.getFormat("HH:mm");
812                 String datePart = dateFormatter.format(convertedDate);
813                 String timePart = timeFormatter.format(convertedDate);
814                 return datePart + " " + timePart;
815         }
816         
817         /**
818          * History support for folder navigation
819          * adds a new browser history entry
820          *
821          * @param key
822          */
823         public void updateHistory(String key){
824 //              Replace any whitespace of the initial string to "+"
825 //              String result = key.replaceAll("\\s","+");
826 //              Add a new browser history entry.
827 //              History.newItem(result);
828                 History.newItem(key);
829         }
830
831         /**
832          * This method examines the token input and add a "/" at the end in case it's omitted.
833          * This happens only in Files/trash/, Files/shared/, Files/others.
834          *
835          * @param tokenInput
836          * @return the formated token with a "/" at the end or the same tokenInput parameter
837          */
838
839         private String handleSpecialFolderNames(String tokenInput){
840                 List<String> pathsToCheck = Arrays.asList("Files/trash", "Files/shared", "Files/others");
841                 if(pathsToCheck.contains(tokenInput))
842                         return tokenInput + "/";
843                 return tokenInput;
844
845         }
846
847         /**
848          * Reject illegal resource names, like '.' or '..' or slashes '/'.
849          */
850         static boolean isValidResourceName(String name) {
851                 if (".".equals(name) || "..".equals(name) || name.contains("/"))
852                         return false;
853                 return true;
854         }
855
856         public void putUserToMap(String _userName, String _userFullName){
857                 userFullNameMap.put(_userName, _userFullName);
858         }
859
860         public String findUserFullName(String _userName){
861                 return userFullNameMap.get(_userName);
862         }
863         public String getUserFullName(String _userName) {
864                 
865         if (Pithos.get().findUserFullName(_userName) == null)
866                 //if there is no userFullName found then the map fills with the given _userName,
867                 //so userFullName = _userName
868                 Pithos.get().putUserToMap(_userName, _userName);
869         else if(Pithos.get().findUserFullName(_userName).indexOf('@') != -1){
870                 //if the userFullName = _userName the GetUserCommand updates the userFullName in the map
871                 GetUserCommand guc = new GetUserCommand(_userName);
872                 guc.execute();
873         }
874         return Pithos.get().findUserFullName(_userName);
875         }
876         /**
877          * Retrieve the treeView.
878          *
879          * @return the treeView
880          */
881         public CellTreeView getTreeView() {
882                 return treeView;
883         }
884         
885         public void onResourceUpdate(RestResource resource,boolean clearSelection){
886                 if(resource instanceof RestResourceWrapper || resource instanceof OtherUserResource || resource instanceof TrashResource || resource instanceof SharedResource){
887                         if(getTreeView().getSelection()!=null&&getTreeView().getSelection().getUri().equals(resource.getUri()))
888                                 showFileList(resource,clearSelection);
889                 }
890                 
891         }
892
893     public void deleteFolder(final Folder folder) {
894         String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + folder.getPrefix();
895         RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
896         builder.setHeader("If-Modified-Since", "0");
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 array = json.isArray();
905                         int i = 0;
906                         if (array != null) {
907                             deleteObject(folder, i, array);
908                         }
909                     }
910                 }
911
912                 @Override
913                 public void onError(Request request, Throwable exception) {
914                     Pithos.get().displayError("System error unable to delete folder: " + exception.getMessage());
915                 }
916             });
917         }
918         catch (RequestException e) {
919         }
920     }
921
922     public void deleteObject(final Folder folder, final int i, final JSONArray array) {
923         if (i < array.size()) {
924             JSONObject o = array.get(i).isObject();
925             if (o != null && !o.containsKey("subdir")) {
926                 JSONString name = o.get("name").isString();
927                 String path = "/" + folder.getContainer() + "/" + name.stringValue();
928                 DeleteRequest delete = new DeleteRequest(getApiPath(), getUsername(), path) {
929                     @Override
930                     public void onSuccess(Resource result) {
931                         deleteObject(folder, i + 1, array);
932                     }
933
934                     @Override
935                     public void onError(Throwable t) {
936                         GWT.log("", t);
937                         Pithos.get().displayError("System error unable to delete folder: " + t.getMessage());
938                     }
939                 };
940                 delete.setHeader("X-Auth-Token", getToken());
941                 Scheduler.get().scheduleDeferred(delete);
942             }
943             else {
944                 String subdir = o.get("subdir").isString().stringValue();
945                 subdir = subdir.substring(0, subdir.length() - 1);
946                 String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + subdir;
947                 RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
948                 builder.setHeader("If-Modified-Since", "0");
949                 builder.setHeader("X-Auth-Token", getToken());
950                 try {
951                     builder.sendRequest("", new RequestCallback() {
952                         @Override
953                         public void onResponseReceived(Request request, Response response) {
954                             if (response.getStatusCode() == Response.SC_OK) {
955                                 JSONValue json = JSONParser.parseStrict(response.getText());
956                                 JSONArray array2 = json.isArray();
957                                 if (array2 != null) {
958                                     int l = array.size();
959                                     for (int j=0; j<array2.size(); j++) {
960                                         array.set(l++, array2.get(j));
961                                     }
962                                 }
963                                 deleteObject(folder, i + 1, array);
964                             }
965                         }
966
967                         @Override
968                         public void onError(Request request, Throwable exception) {
969                             Pithos.get().displayError("System error unable to delete folder: " + exception.getMessage());
970                         }
971                     });
972                 }
973                 catch (RequestException e) {
974                 }
975             }
976         }
977         else {
978             String path = folder.getUri();
979             DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), path) {
980                 @Override
981                 public void onSuccess(Resource result) {
982                     updateFolder(folder.getParent());
983                 }
984
985                 @Override
986                 public void onError(Throwable t) {
987                     GWT.log("", t);
988                     if (t instanceof RestException) {
989                         displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText());
990                     }
991                     else
992                         Pithos.get().displayError("System error unable to delete folder: " + t.getMessage());
993                 }
994             };
995             deleteFolder.setHeader("X-Auth-Token", getToken());
996             Scheduler.get().scheduleDeferred(deleteFolder);
997         }
998     }
999
1000     public FolderTreeView getFolderTreeView() {
1001         return folderTreeView;
1002     }
1003
1004     public void copyFiles(final Iterator<File> iter, final String targetUri, final Command callback) {
1005         if (iter.hasNext()) {
1006             File file = iter.next();
1007             String path = targetUri + "/" + file.getName();
1008             PutRequest copyFile = new PutRequest(getApiPath(), getUsername(), path) {
1009                 @Override
1010                 public void onSuccess(Resource result) {
1011                     copyFiles(iter, targetUri, callback);
1012                 }
1013
1014                 @Override
1015                 public void onError(Throwable t) {
1016                     GWT.log("", t);
1017                     if (t instanceof RestException) {
1018                         Pithos.get().displayError("Unable to copy file: " + ((RestException) t).getHttpStatusText());
1019                     }
1020                     else
1021                         Pithos.get().displayError("System error unable to copy file: "+t.getMessage());
1022                 }
1023             };
1024             copyFile.setHeader("X-Auth-Token", getToken());
1025             copyFile.setHeader("X-Copy-From", file.getUri());
1026             Scheduler.get().scheduleDeferred(copyFile);
1027         }
1028         else  if (callback != null) {
1029             callback.execute();
1030         }
1031     }
1032
1033     public void copySubfolders(final Iterator<Folder> iter, final String targetUri, final Command callback) {
1034         if (iter.hasNext()) {
1035             final Folder f = iter.next();
1036             copyFolder(f, targetUri, callback);
1037         }
1038         else  if (callback != null) {
1039             callback.execute();
1040         }
1041     }
1042
1043     public void copyFolder(final Folder f, final String targetUri, final Command callback) {
1044         String path = targetUri + "/" + f.getName();
1045         PutRequest createFolder = new PutRequest(getApiPath(), getUsername(), path) {
1046             @Override
1047             public void onSuccess(Resource result) {
1048                 Iterator<File> iter = f.getFiles().iterator();
1049                 copyFiles(iter, targetUri + "/" + f.getName(), new Command() {
1050                     @Override
1051                     public void execute() {
1052                         Iterator<Folder> iterf = f.getSubfolders().iterator();
1053                         copySubfolders(iterf, targetUri + "/" + f.getName(), new Command() {
1054                             @Override
1055                             public void execute() {
1056                                 callback.execute();
1057                             }
1058                         });
1059                     }
1060                 });
1061             }
1062
1063             @Override
1064             public void onError(Throwable t) {
1065                 GWT.log("", t);
1066                 if (t instanceof RestException) {
1067                     displayError("Unable to create folder:" + ((RestException) t).getHttpStatusText());
1068                 }
1069                 else
1070                     displayError("System error creating folder:" + t.getMessage());
1071             }
1072         };
1073         createFolder.setHeader("X-Auth-Token", getToken());
1074         createFolder.setHeader("Accept", "*/*");
1075         createFolder.setHeader("Content-Length", "0");
1076         createFolder.setHeader("Content-Type", "application/folder");
1077         Scheduler.get().scheduleDeferred(createFolder);
1078     }
1079 }