Statistics
| Branch: | Tag: | Revision:

root / web_client / src / gr / grnet / pithos / web / client / Pithos.java @ e9c9f408

History | View | Annotate | Download (34.3 kB)

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, 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 Application Clipboard implementation;
176
         */
177
        private Clipboard clipboard = new Clipboard();
178

    
179
        private UserResource currentUserResource;
180

    
181
        /**
182
         * The top panel that contains the menu bar.
183
         */
184
        private TopPanel topPanel;
185

    
186
        /**
187
         * The panel that contains the various system messages.
188
         */
189
        private MessagePanel messagePanel = new MessagePanel(Pithos.images);
190

    
191
        /**
192
         * The bottom panel that contains the status bar.
193
         */
194
        private StatusPanel statusPanel = null;
195

    
196
        /**
197
         * The top right panel that displays the logged in user details
198
         */
199
        private UserDetailsPanel userDetailsPanel = new UserDetailsPanel(this);
200

    
201
        /**
202
         * The file list widget.
203
         */
204
        private FileList fileList;
205

    
206
        /**
207
         * The tab panel that occupies the right side of the screen.
208
         */
209
        private TabPanel inner = new DecoratedTabPanel(){
210
                
211
//                public void onBrowserEvent(com.google.gwt.user.client.Event event) {
212
//                        if (DOM.eventGetType(event) == Event.ONCONTEXTMENU){
213
//                                if(isFileListShowing()){
214
//                                        getFileList().showContextMenu(event);
215
//                                }
216
//                        }
217
//                };
218
        };
219

    
220

    
221
        /**
222
         * The split panel that will contain the left and right panels.
223
         */
224
        private HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
225

    
226
        /**
227
         * The widget that displays the tree of folders.
228
         */
229
        
230
        private CellTreeView treeView = null;
231
        /**
232
         * The currently selected item in the application, for use by the Edit menu
233
         * commands. Potential types are Folder, File, User and Group.
234
         */
235
        private Object currentSelection;
236

    
237

    
238
        /**
239
         * The WebDAV password of the current user
240
         */
241
        private String webDAVPassword;
242

    
243
        public HashMap<String, String> userFullNameMap = new HashMap<String, String>();
244

    
245
    private String username = null;
246

    
247
    /**
248
     * The authentication token of the current user.
249
     */
250
    private String token;
251

    
252
    private SingleSelectionModel<Folder> folderTreeSelectionModel;
253
    private FolderTreeViewModel folderTreeViewModel;
254
    private FolderTreeView folderTreeView;
255

    
256
    private SingleSelectionModel<Tag> tagTreeSelectionModel;
257
    private TagTreeViewModel tagTreeViewModel;
258
    private TagTreeView tagTreeView;
259

    
260
    private AccountResource account;
261

    
262
        @Override
263
        public void onModuleLoad() {
264
                if (parseUserCredentials())
265
            initialize();
266
        }
267

    
268
    private void initialize() {
269
        topPanel = new TopPanel(this, Pithos.images);
270
        topPanel.setWidth("100%");
271

    
272
        messagePanel.setWidth("100%");
273
        messagePanel.setVisible(false);
274

    
275

    
276
        // Inner contains the various lists.
277
        inner.sinkEvents(Event.ONCONTEXTMENU);
278
        inner.setAnimationEnabled(true);
279
        inner.getTabBar().addStyleName("pithos-MainTabBar");
280
        inner.getDeckPanel().addStyleName("pithos-MainTabPanelBottom");
281

    
282
        inner.setWidth("100%");
283

    
284
        inner.addSelectionHandler(new SelectionHandler<Integer>() {
285

    
286
            @Override
287
            public void onSelection(SelectionEvent<Integer> event) {
288
                int tabIndex = event.getSelectedItem();
289
                switch (tabIndex) {
290
                    case 0:
291
                        fileList.updateCurrentlyShowingStats();
292
                        break;
293
                }
294
            }
295
        });
296

    
297
        folderTreeSelectionModel = new SingleSelectionModel<Folder>();
298
        folderTreeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
299
            @Override
300
            public void onSelectionChange(SelectionChangeEvent event) {
301
                if (folderTreeSelectionModel.getSelectedObject() != null) {
302
                    tagTreeSelectionModel.setSelected(tagTreeSelectionModel.getSelectedObject(), false);
303
                    Folder f = folderTreeSelectionModel.getSelectedObject();
304
                    updateFolder(f);
305
                }
306
            }
307
        });
308

    
309
        folderTreeViewModel = new FolderTreeViewModel(this, folderTreeSelectionModel);
310
        folderTreeView = new FolderTreeView(folderTreeViewModel);
311

    
312
        fileList = new FileList(this, images, folderTreeView);
313
        inner.add(fileList, createHeaderHTML(AbstractImagePrototype.create(images.folders()), "Files"), true);
314

    
315
        tagTreeSelectionModel = new SingleSelectionModel<Tag>();
316
        tagTreeSelectionModel.addSelectionChangeHandler(new Handler() {
317
            @Override
318
            public void onSelectionChange(SelectionChangeEvent event) {
319
                if (tagTreeSelectionModel.getSelectedObject() != null) {
320
                    folderTreeSelectionModel.setSelected(folderTreeSelectionModel.getSelectedObject(), false);
321
                    Tag t = tagTreeSelectionModel.getSelectedObject();
322
                    updateTag(t);
323
                }
324
            }
325
        });
326
        tagTreeViewModel = new TagTreeViewModel(this, tagTreeSelectionModel);
327
        tagTreeView = new TagTreeView(tagTreeViewModel);
328

    
329
        VerticalPanel trees = new VerticalPanel();
330
        trees.add(folderTreeView);
331
        trees.add(tagTreeView);
332
        // Add the left and right panels to the split panel.
333
        splitPanel.setLeftWidget(trees);
334
        splitPanel.setRightWidget(inner);
335
        splitPanel.setSplitPosition("25%");
336
        splitPanel.setSize("100%", "100%");
337
        splitPanel.addStyleName("pithos-splitPanel");
338

    
339
        // Create a dock panel that will contain the menu bar at the top,
340
        // the shortcuts to the left, the status bar at the bottom and the
341
        // right panel taking the rest.
342
        VerticalPanel outer = new VerticalPanel();
343
        outer.add(topPanel);
344
        outer.add(messagePanel);
345
        outer.add(splitPanel);
346
        statusPanel = new StatusPanel(this, Pithos.images);
347
        outer.add(statusPanel);
348
        outer.setWidth("100%");
349
        outer.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER);
350

    
351
        outer.setSpacing(4);
352

    
353
        // Hook the window resize event, so that we can adjust the UI.
354
        Window.addResizeHandler(this);
355
        // Clear out the window's built-in margin, because we want to take
356
        // advantage of the entire client area.
357
        Window.setMargin("0px");
358
        // Finally, add the outer panel to the RootPanel, so that it will be
359
        // displayed.
360
        RootPanel.get().add(outer);
361
        // Call the window resized handler to get the initial sizes setup. Doing
362
        // this in a deferred command causes it to occur after all widgets'
363
        // sizes have been computed by the browser.
364
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
365

    
366
            @Override
367
            public void execute() {
368
                onWindowResized(Window.getClientHeight());
369
            }
370
        });
371

    
372
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
373
            @Override
374
            public void execute() {
375
                fetchAccount();
376
            }
377
        });
378
    }
379

    
380
    public void showFiles(Folder f) {
381
        inner.selectTab(0);
382
        if (f.isTrash()) {
383
            fileList.showTrash();
384
        }
385
        else
386
            fileList.showFiles();
387
        Set<File> files = f.getFiles();
388
        showFiles(files);
389
    }
390

    
391
    public void showFiles(Set<File> files) {
392
        //Iterator<File> iter = files.iterator();
393
        //fetchFile(iter, files);
394
        fileList.setFiles(new ArrayList<File>(files));
395
    }
396

    
397
    private void fetchFile(final Iterator<File> iter, final Set<File> files) {
398
        if (iter.hasNext()) {
399
            File file = iter.next();
400
            String path = file.getUri() + "?format=json";
401
            GetRequest<File> getFile = new GetRequest<File>(File.class, getApiPath(), username, path, file) {
402
                @Override
403
                public void onSuccess(File result) {
404
                    fetchFile(iter, files);
405
                }
406

    
407
                @Override
408
                public void onError(Throwable t) {
409
                    GWT.log("Error getting file", t);
410
                    if (t instanceof RestException)
411
                        displayError("Error getting file: " + ((RestException) t).getHttpStatusText());
412
                    else
413
                        displayError("System error fetching file: " + t.getMessage());
414
                }
415
            };
416
            getFile.setHeader("X-Auth-Token", "0000");
417
            Scheduler.get().scheduleDeferred(getFile);
418
        }
419
        else
420
            fileList.setFiles(new ArrayList<File>(files));
421
    }
422

    
423
    /**
424
         * Parse and store the user credentials to the appropriate fields.
425
         */
426
        private boolean parseUserCredentials() {
427
                Configuration conf = (Configuration) GWT.create(Configuration.class);
428
                String cookie = conf.authCookie();
429
                String auth = Cookies.getCookie(cookie);
430
                if (auth == null) {
431
                        authenticateUser();
432
            return false;
433
        }
434
        else {
435
            String[] authSplit = auth.split("\\" + conf.cookieSeparator(), 2);
436
            if (authSplit.length != 2) {
437
                authenticateUser();
438
                return false;
439
            }
440
            else {
441
                username = authSplit[0];
442
                token = authSplit[1];
443
                return true;
444
            }
445
        }
446
        }
447

    
448
    /**
449
         * Redirect the user to the login page for authentication.
450
         */
451
        protected void authenticateUser() {
452
                Configuration conf = (Configuration) GWT.create(Configuration.class);
453

    
454
//        Window.Location.assign(GWT.getModuleBaseURL() + conf.loginUrl() + "?next=" + Window.Location.getHref());
455
        Cookies.setCookie(conf.authCookie(), "test" + conf.cookieSeparator() + "0000");
456
        Window.Location.assign(GWT.getModuleBaseURL() + "pithos.html");
457
        }
458

    
459
    private void fetchAccount() {
460
        String path = "?format=json";
461

    
462
        GetRequest<AccountResource> getAccount = new GetRequest<AccountResource>(AccountResource.class, getApiPath(), username, path) {
463
            @Override
464
            public void onSuccess(AccountResource result) {
465
                account = result;
466
                statusPanel.displayStats(account);
467
                inner.selectTab(0);
468
                if (account.getContainers().isEmpty())
469
                    createHomeContainers();
470
                else
471
                    folderTreeViewModel.initialize(account);
472
            }
473

    
474
            @Override
475
            public void onError(Throwable t) {
476
                GWT.log("Error getting account", t);
477
                if (t instanceof RestException)
478
                    displayError("Error getting account: " + ((RestException) t).getHttpStatusText());
479
                else
480
                    displayError("System error fetching user data: " + t.getMessage());
481
            }
482
        };
483
        getAccount.setHeader("X-Auth-Token", token);
484
        Scheduler.get().scheduleDeferred(getAccount);
485
    }
486

    
487
    private void createHomeContainers() {
488
        String path = "/pithos";
489
        PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
490
            @Override
491
            public void onSuccess(Resource result) {
492
                fetchAccount();
493
            }
494

    
495
            @Override
496
            public void onError(Throwable t) {
497
                GWT.log("Error creating pithos", t);
498
                if (t instanceof RestException)
499
                    displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText());
500
                else
501
                    displayError("System error Error creating pithos: " + t.getMessage());
502
            }
503
        };
504
        createPithos.setHeader("X-Auth-Token", getToken());
505
        Scheduler.get().scheduleDeferred(createPithos);
506
    }
507

    
508
        /**
509
         * Clear the cookie and redirect the user to the logout page.
510
         */
511
        void logout() {
512
                Configuration conf = (Configuration) GWT.create(Configuration.class);
513
                String cookie = conf.authCookie();
514
                String domain = Window.Location.getHostName();
515
                String path = Window.Location.getPath();
516
                Cookies.setCookie(cookie, "", null, domain, path, false);
517
        String baseUrl = GWT.getModuleBaseURL();
518
        String homeUrl = baseUrl.substring(0, baseUrl.indexOf(path));
519
                Window.Location.assign(homeUrl + conf.logoutUrl());
520
        }
521

    
522
        /**
523
         * Creates an HTML fragment that places an image & caption together, for use
524
         * in a group header.
525
         *
526
         * @param imageProto an image prototype for an image
527
         * @param caption the group caption
528
         * @return the header HTML fragment
529
         */
530
        private String createHeaderHTML(AbstractImagePrototype imageProto, String caption) {
531
                String captionHTML = "<table class='caption' cellpadding='0' " 
532
                + "cellspacing='0'>" + "<tr><td class='lcaption'>" + imageProto.getHTML() 
533
                + "</td><td id =" + caption +" class='rcaption'><b style='white-space:nowrap'>&nbsp;" 
534
                + caption + "</b></td></tr></table>";
535
                return captionHTML;
536
        }
537

    
538
        private void onWindowResized(int height) {
539
                // Adjust the split panel to take up the available room in the window.
540
                int newHeight = height - splitPanel.getAbsoluteTop() - 44;
541
                if (newHeight < 1)
542
                        newHeight = 1;
543
                splitPanel.setHeight("" + newHeight);
544
                inner.setHeight("" + newHeight);
545
        }
546

    
547
        @Override
548
        public void onResize(ResizeEvent event) {
549
                int height = event.getHeight();
550
                onWindowResized(height);
551
        }
552

    
553
        public boolean isFileListShowing() {
554
                int tab = inner.getTabBar().getSelectedTab();
555
                if (tab == 0)
556
                        return true;
557
                return false;
558
        }
559

    
560
        public boolean isSearchResultsShowing() {
561
                int tab = inner.getTabBar().getSelectedTab();
562
                if (tab == 2)
563
                        return true;
564
                return false;
565
        }
566

    
567
        /**
568
         * Make the file list visible.
569
         *
570
         * @param update
571
         */
572
        public void showFileList(boolean update) {
573
                if(update){
574
                        getTreeView().refreshCurrentNode(true);
575
                }
576
                else{
577
                        RestResource currentFolder = getTreeView().getSelection();
578
                        if(currentFolder!=null){
579
                                showFileList(currentFolder);
580
                }
581
                }
582

    
583
        }
584
        
585
        public void showFileList(RestResource r) {
586
                showFileList(r,true);
587
        }
588
        
589
        public void showFileList(RestResource r, boolean clearSelection) {
590
                RestResource currentFolder = r;
591
                if(currentFolder!=null){
592
                        List<FileResource> files = null;
593
                        if (currentFolder instanceof RestResourceWrapper) {
594
                                RestResourceWrapper folder = (RestResourceWrapper) currentFolder;
595
                                files = folder.getResource().getFiles();
596
                        }
597
                }
598
                inner.selectTab(0);
599
        }
600

    
601
        /**
602
         * Display the 'loading' indicator.
603
         */
604
        public void showLoadingIndicator(String message, String path) {
605
                if(path!=null){
606
                        String[] split = path.split("/");
607
                        message = message +" "+URL.decode(split[split.length-1]);
608
                }
609
                topPanel.getLoading().show(message);
610
        }
611

    
612
        /**
613
         * Hide the 'loading' indicator.
614
         */
615
        public void hideLoadingIndicator() {
616
                topPanel.getLoading().hide();
617
        }
618

    
619
        /**
620
         * A native JavaScript method to reach out to the browser's window and
621
         * invoke its resizeTo() method.
622
         *
623
         * @param x the new width
624
         * @param y the new height
625
         */
626
        public static native void resizeTo(int x, int y) /*-{
627
                $wnd.resizeTo(x,y);
628
        }-*/;
629

    
630
        /**
631
         * A helper method that returns true if the user's list is currently visible
632
         * and false if it is hidden.
633
         *
634
         * @return true if the user list is visible
635
         */
636
        public boolean isUserListVisible() {
637
                return inner.getTabBar().getSelectedTab() == 1;
638
        }
639

    
640
        /**
641
         * Display an error message.
642
         *
643
         * @param msg the message to display
644
         */
645
        public void displayError(String msg) {
646
                messagePanel.displayError(msg);
647
        }
648

    
649
        /**
650
         * Display a warning message.
651
         *
652
         * @param msg the message to display
653
         */
654
        public void displayWarning(String msg) {
655
                messagePanel.displayWarning(msg);
656
        }
657

    
658
        /**
659
         * Display an informational message.
660
         *
661
         * @param msg the message to display
662
         */
663
        public void displayInformation(String msg) {
664
                messagePanel.displayInformation(msg);
665
        }
666

    
667
        /**
668
         * Retrieve the folders.
669
         *
670
         * @return the folders
671
         
672
        public Folders getFolders() {
673
                return folders;
674
        }*/
675

    
676
        /**
677
         * Retrieve the currentSelection.
678
         *
679
         * @return the currentSelection
680
         */
681
        public Object getCurrentSelection() {
682
                return currentSelection;
683
        }
684

    
685
        /**
686
         * Modify the currentSelection.
687
         *
688
         * @param newCurrentSelection the currentSelection to set
689
         */
690
        public void setCurrentSelection(Object newCurrentSelection) {
691
                currentSelection = newCurrentSelection;
692
        }
693

    
694
        /**
695
         * Retrieve the fileList.
696
         *
697
         * @return the fileList
698
         */
699
        public FileList getFileList() {
700
                return fileList;
701
        }
702

    
703
        /**
704
         * Retrieve the topPanel.
705
         *
706
         * @return the topPanel
707
         */
708
        TopPanel getTopPanel() {
709
                return topPanel;
710
        }
711

    
712
        /**
713
         * Retrieve the clipboard.
714
         *
715
         * @return the clipboard
716
         */
717
        public Clipboard getClipboard() {
718
                return clipboard;
719
        }
720

    
721
        public StatusPanel getStatusPanel() {
722
                return statusPanel;
723
        }
724

    
725
        /**
726
         * Retrieve the userDetailsPanel.
727
         *
728
         * @return the userDetailsPanel
729
         */
730
        public UserDetailsPanel getUserDetailsPanel() {
731
                return userDetailsPanel;
732
        }
733

    
734
        
735

    
736
        public String getToken() {
737
                return token;
738
        }
739

    
740
        public String getWebDAVPassword() {
741
                return webDAVPassword;
742
        }
743

    
744
        /**
745
         * Retrieve the currentUserResource.
746
         *
747
         * @return the currentUserResource
748
         */
749
        public UserResource getCurrentUserResource() {
750
                return currentUserResource;
751
        }
752

    
753
        /**
754
         * Modify the currentUserResource.
755
         *
756
         * @param newUser the new currentUserResource
757
         */
758
        public void setCurrentUserResource(UserResource newUser) {
759
                currentUserResource = newUser;
760
        }
761

    
762
        public static native void preventIESelection() /*-{
763
                $doc.body.onselectstart = function () { return false; };
764
        }-*/;
765

    
766
        public static native void enableIESelection() /*-{
767
                if ($doc.body.onselectstart != null)
768
                $doc.body.onselectstart = null;
769
        }-*/;
770

    
771
        /**
772
         * @return the absolute path of the API root URL
773
         */
774
        public String getApiPath() {
775
                Configuration conf = (Configuration) GWT.create(Configuration.class);
776
                return conf.apiPath();
777
        }
778

    
779
        /**
780
         * Convert server date to local time according to browser timezone
781
         * and format it according to localized pattern.
782
         * Time is always formatted to 24hr format.
783
         * NB: This assumes that server runs in UTC timezone. Otherwise
784
         * we would need to adjust for server time offset as well.
785
         *
786
         * @param date
787
         * @return String
788
         */
789
        public static String formatLocalDateTime(Date date) {
790
                Date convertedDate = new Date(date.getTime() - date.getTimezoneOffset());
791
                final DateTimeFormat dateFormatter = DateTimeFormat.getShortDateFormat();
792
                final DateTimeFormat timeFormatter = DateTimeFormat.getFormat("HH:mm");
793
                String datePart = dateFormatter.format(convertedDate);
794
                String timePart = timeFormatter.format(convertedDate);
795
                return datePart + " " + timePart;
796
        }
797
        
798
        /**
799
         * History support for folder navigation
800
         * adds a new browser history entry
801
         *
802
         * @param key
803
         */
804
        public void updateHistory(String key){
805
//                Replace any whitespace of the initial string to "+"
806
//                String result = key.replaceAll("\\s","+");
807
//                Add a new browser history entry.
808
//                History.newItem(result);
809
                History.newItem(key);
810
        }
811

    
812
        /**
813
         * This method examines the token input and add a "/" at the end in case it's omitted.
814
         * This happens only in Files/trash/, Files/shared/, Files/others.
815
         *
816
         * @param tokenInput
817
         * @return the formated token with a "/" at the end or the same tokenInput parameter
818
         */
819

    
820
        private String handleSpecialFolderNames(String tokenInput){
821
                List<String> pathsToCheck = Arrays.asList("Files/trash", "Files/shared", "Files/others");
822
                if(pathsToCheck.contains(tokenInput))
823
                        return tokenInput + "/";
824
                return tokenInput;
825

    
826
        }
827

    
828
        /**
829
         * Reject illegal resource names, like '.' or '..' or slashes '/'.
830
         */
831
        static boolean isValidResourceName(String name) {
832
                if (".".equals(name) ||        "..".equals(name) || name.contains("/"))
833
                        return false;
834
                return true;
835
        }
836

    
837
        public void putUserToMap(String _userName, String _userFullName){
838
                userFullNameMap.put(_userName, _userFullName);
839
        }
840

    
841
        public String findUserFullName(String _userName){
842
                return userFullNameMap.get(_userName);
843
        }
844

    
845
        /**
846
         * Retrieve the treeView.
847
         *
848
         * @return the treeView
849
         */
850
        public CellTreeView getTreeView() {
851
                return treeView;
852
        }
853
        
854
        public void onResourceUpdate(RestResource resource,boolean clearSelection){
855
                if(resource instanceof RestResourceWrapper || resource instanceof OtherUserResource || resource instanceof TrashResource || resource instanceof SharedResource){
856
                        if(getTreeView().getSelection()!=null&&getTreeView().getSelection().getUri().equals(resource.getUri()))
857
                                showFileList(resource,clearSelection);
858
                }
859
                
860
        }
861

    
862
    public void deleteFolder(final Folder folder) {
863
        String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + folder.getPrefix();
864
        RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
865
        builder.setHeader("If-Modified-Since", "0");
866
        builder.setHeader("X-Auth-Token", getToken());
867
        try {
868
            builder.sendRequest("", new RequestCallback() {
869
                @Override
870
                public void onResponseReceived(Request request, Response response) {
871
                    if (response.getStatusCode() == Response.SC_OK) {
872
                        JSONValue json = JSONParser.parseStrict(response.getText());
873
                        JSONArray array = json.isArray();
874
                        int i = 0;
875
                        if (array != null) {
876
                            deleteObject(folder, i, array);
877
                        }
878
                    }
879
                }
880

    
881
                @Override
882
                public void onError(Request request, Throwable exception) {
883
                    displayError("System error unable to delete folder: " + exception.getMessage());
884
                }
885
            });
886
        }
887
        catch (RequestException e) {
888
        }
889
    }
890

    
891
    public void deleteObject(final Folder folder, final int i, final JSONArray array) {
892
        if (i < array.size()) {
893
            JSONObject o = array.get(i).isObject();
894
            if (o != null && !o.containsKey("subdir")) {
895
                JSONString name = o.get("name").isString();
896
                String path = "/" + folder.getContainer() + "/" + name.stringValue();
897
                DeleteRequest delete = new DeleteRequest(getApiPath(), getUsername(), path) {
898
                    @Override
899
                    public void onSuccess(Resource result) {
900
                        deleteObject(folder, i + 1, array);
901
                    }
902

    
903
                    @Override
904
                    public void onError(Throwable t) {
905
                        GWT.log("", t);
906
                        displayError("System error unable to delete folder: " + t.getMessage());
907
                    }
908
                };
909
                delete.setHeader("X-Auth-Token", getToken());
910
                Scheduler.get().scheduleDeferred(delete);
911
            }
912
            else {
913
                String subdir = o.get("subdir").isString().stringValue();
914
                subdir = subdir.substring(0, subdir.length() - 1);
915
                String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + subdir;
916
                RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
917
                builder.setHeader("If-Modified-Since", "0");
918
                builder.setHeader("X-Auth-Token", getToken());
919
                try {
920
                    builder.sendRequest("", new RequestCallback() {
921
                        @Override
922
                        public void onResponseReceived(Request request, Response response) {
923
                            if (response.getStatusCode() == Response.SC_OK) {
924
                                JSONValue json = JSONParser.parseStrict(response.getText());
925
                                JSONArray array2 = json.isArray();
926
                                if (array2 != null) {
927
                                    int l = array.size();
928
                                    for (int j=0; j<array2.size(); j++) {
929
                                        array.set(l++, array2.get(j));
930
                                    }
931
                                }
932
                                deleteObject(folder, i + 1, array);
933
                            }
934
                        }
935

    
936
                        @Override
937
                        public void onError(Request request, Throwable exception) {
938
                            displayError("System error unable to delete folder: " + exception.getMessage());
939
                        }
940
                    });
941
                }
942
                catch (RequestException e) {
943
                }
944
            }
945
        }
946
        else {
947
            String path = folder.getUri();
948
            DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), path) {
949
                @Override
950
                public void onSuccess(Resource result) {
951
                    updateFolder(folder.getParent());
952
                }
953

    
954
                @Override
955
                public void onError(Throwable t) {
956
                    GWT.log("", t);
957
                    if (t instanceof RestException) {
958
                        displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText());
959
                    }
960
                    else
961
                        displayError("System error unable to delete folder: " + t.getMessage());
962
                }
963
            };
964
            deleteFolder.setHeader("X-Auth-Token", getToken());
965
            Scheduler.get().scheduleDeferred(deleteFolder);
966
        }
967
    }
968

    
969
    public FolderTreeView getFolderTreeView() {
970
        return folderTreeView;
971
    }
972

    
973
    public void copyFiles(final Iterator<File> iter, final String targetUri, final Command callback) {
974
        if (iter.hasNext()) {
975
            File file = iter.next();
976
            String path = targetUri + "/" + file.getName();
977
            PutRequest copyFile = new PutRequest(getApiPath(), getUsername(), path) {
978
                @Override
979
                public void onSuccess(Resource result) {
980
                    copyFiles(iter, targetUri, callback);
981
                }
982

    
983
                @Override
984
                public void onError(Throwable t) {
985
                    GWT.log("", t);
986
                    if (t instanceof RestException) {
987
                        displayError("Unable to copy file: " + ((RestException) t).getHttpStatusText());
988
                    }
989
                    else
990
                        displayError("System error unable to copy file: "+t.getMessage());
991
                }
992
            };
993
            copyFile.setHeader("X-Auth-Token", getToken());
994
            copyFile.setHeader("X-Copy-From", file.getUri());
995
            Scheduler.get().scheduleDeferred(copyFile);
996
        }
997
        else  if (callback != null) {
998
            callback.execute();
999
        }
1000
    }
1001

    
1002
    public void copySubfolders(final Iterator<Folder> iter, final String targetUri, final Command callback) {
1003
        if (iter.hasNext()) {
1004
            final Folder f = iter.next();
1005
            copyFolder(f, targetUri, callback);
1006
        }
1007
        else  if (callback != null) {
1008
            callback.execute();
1009
        }
1010
    }
1011

    
1012
    public void copyFolder(final Folder f, final String targetUri, final Command callback) {
1013
        String path = targetUri + "/" + f.getName();
1014
        PutRequest createFolder = new PutRequest(getApiPath(), getUsername(), path) {
1015
            @Override
1016
            public void onSuccess(Resource result) {
1017
                Iterator<File> iter = f.getFiles().iterator();
1018
                copyFiles(iter, targetUri + "/" + f.getName(), new Command() {
1019
                    @Override
1020
                    public void execute() {
1021
                        Iterator<Folder> iterf = f.getSubfolders().iterator();
1022
                        copySubfolders(iterf, targetUri + "/" + f.getName(), new Command() {
1023
                            @Override
1024
                            public void execute() {
1025
                                callback.execute();
1026
                            }
1027
                        });
1028
                    }
1029
                });
1030
            }
1031

    
1032
            @Override
1033
            public void onError(Throwable t) {
1034
                GWT.log("", t);
1035
                if (t instanceof RestException) {
1036
                    displayError("Unable to create folder:" + ((RestException) t).getHttpStatusText());
1037
                }
1038
                else
1039
                    displayError("System error creating folder:" + t.getMessage());
1040
            }
1041
        };
1042
        createFolder.setHeader("X-Auth-Token", getToken());
1043
        createFolder.setHeader("Accept", "*/*");
1044
        createFolder.setHeader("Content-Length", "0");
1045
        createFolder.setHeader("Content-Type", "application/folder");
1046
        Scheduler.get().scheduleDeferred(createFolder);
1047
    }
1048
}