Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (34.1 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 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.grouptree.User;
48
import gr.grnet.pithos.web.client.mysharedtree.MysharedTreeView;
49
import gr.grnet.pithos.web.client.mysharedtree.MysharedTreeViewModel;
50
import gr.grnet.pithos.web.client.othersharedtree.OtherSharedTreeView;
51
import gr.grnet.pithos.web.client.othersharedtree.OtherSharedTreeViewModel;
52
import gr.grnet.pithos.web.client.rest.DeleteRequest;
53
import gr.grnet.pithos.web.client.rest.GetRequest;
54
import gr.grnet.pithos.web.client.rest.PutRequest;
55
import gr.grnet.pithos.web.client.rest.RestException;
56
import gr.grnet.pithos.web.client.tagtree.Tag;
57
import gr.grnet.pithos.web.client.tagtree.TagTreeView;
58
import gr.grnet.pithos.web.client.tagtree.TagTreeViewModel;
59

    
60
import java.util.ArrayList;
61
import java.util.HashMap;
62
import java.util.Iterator;
63
import java.util.List;
64
import java.util.Set;
65

    
66
import com.google.gwt.core.client.EntryPoint;
67
import com.google.gwt.core.client.GWT;
68
import com.google.gwt.core.client.Scheduler;
69
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
70
import com.google.gwt.event.dom.client.ClickEvent;
71
import com.google.gwt.event.dom.client.ClickHandler;
72
import com.google.gwt.event.logical.shared.ResizeEvent;
73
import com.google.gwt.event.logical.shared.ResizeHandler;
74
import com.google.gwt.http.client.Request;
75
import com.google.gwt.http.client.RequestBuilder;
76
import com.google.gwt.http.client.RequestCallback;
77
import com.google.gwt.http.client.RequestException;
78
import com.google.gwt.http.client.Response;
79
import com.google.gwt.json.client.JSONArray;
80
import com.google.gwt.json.client.JSONObject;
81
import com.google.gwt.json.client.JSONParser;
82
import com.google.gwt.json.client.JSONString;
83
import com.google.gwt.json.client.JSONValue;
84
import com.google.gwt.resources.client.ImageResource;
85
import com.google.gwt.user.client.Command;
86
import com.google.gwt.user.client.Cookies;
87
import com.google.gwt.user.client.Event;
88
import com.google.gwt.user.client.History;
89
import com.google.gwt.user.client.Window;
90
import com.google.gwt.user.client.ui.AbstractImagePrototype;
91
import com.google.gwt.user.client.ui.Button;
92
import com.google.gwt.user.client.ui.HTML;
93
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
94
import com.google.gwt.user.client.ui.HasVerticalAlignment;
95
import com.google.gwt.user.client.ui.HorizontalPanel;
96
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
97
import com.google.gwt.user.client.ui.Image;
98
import com.google.gwt.user.client.ui.PushButton;
99
import com.google.gwt.user.client.ui.RootPanel;
100
import com.google.gwt.user.client.ui.VerticalPanel;
101
import com.google.gwt.view.client.SelectionChangeEvent;
102
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
103
import com.google.gwt.view.client.SingleSelectionModel;
104

    
105
/**
106
 * Entry point classes define <code>onModuleLoad()</code>.
107
 */
108
public class Pithos implements EntryPoint, ResizeHandler {
109

    
110
        public static final String HOME_CONTAINER = "pithos";
111

    
112
        public static final String TRASH_CONTAINER = "trash";
113
        
114
        /**
115
         * Instantiate an application-level image bundle. This object will provide
116
         * programmatic access to all the images needed by widgets.
117
         */
118
        private static Images images = (Images) GWT.create(Images.class);
119

    
120
    public String getUsername() {
121
        return username;
122
    }
123

    
124
    public void setAccount(AccountResource acct) {
125
        account = acct;
126
    }
127

    
128
    public AccountResource getAccount() {
129
        return account;
130
    }
131

    
132
    public void updateFolder(Folder f, boolean showfiles, Command callback) {
133
        folderTreeView.updateFolder(f, showfiles, callback);
134
    }
135

    
136
    public void updateGroupNode(Group group) {
137
        groupTreeView.updateGroupNode(group);
138
    }
139

    
140
    public void updateSharedFolder(Folder f, boolean showfiles) {
141
            mysharedTreeView.updateFolder(f, showfiles);
142
    }
143
    
144
    public void updateOtherSharedFolder(Folder f, boolean showfiles) {
145
            otherSharedTreeView.updateFolder(f, showfiles);
146
    }
147

    
148
    public void updateTag(Tag t) {
149
        tagTreeView.updateTag(t);
150
    }
151

    
152
    public void updateTags() {
153
        tagTreeViewModel.initialize(getAllTags());
154
    }
155

    
156
    public List<Tag> getAllTags() {
157
        List<Tag> tagList = new ArrayList<Tag>();
158
        for (Folder f : account.getContainers()) {
159
            for (String t : f.getTags()) {
160
                tagList.add(new Tag(t));
161
            }
162
        }
163
        return tagList;
164
    }
165

    
166
    public MysharedTreeView getMySharedTreeView() {
167
        return mysharedTreeView;
168
    }
169

    
170
    /**
171
         * An aggregate image bundle that pulls together all the images for this
172
         * application into a single bundle.
173
         */
174
        public interface Images extends TopPanel.Images, FileList.Images {
175

    
176
                @Source("gr/grnet/pithos/resources/document.png")
177
                ImageResource folders();
178

    
179
                @Source("gr/grnet/pithos/resources/edit_group_22.png")
180
                ImageResource groups();
181

    
182
                @Source("gr/grnet/pithos/resources/search.png")
183
                ImageResource search();
184
        }
185

    
186
        /**
187
         * The Application Clipboard implementation;
188
         */
189
        private Clipboard clipboard = new Clipboard();
190

    
191
        /**
192
         * The top panel that contains the menu bar.
193
         */
194
        private TopPanel topPanel;
195

    
196
        /**
197
         * The panel that contains the various system messages.
198
         */
199
        private MessagePanel messagePanel = new MessagePanel(Pithos.images);
200

    
201
        /**
202
         * The bottom panel that contains the status bar.
203
         */
204
        private StatusPanel statusPanel = null;
205

    
206
        /**
207
         * The file list widget.
208
         */
209
        private FileList fileList;
210

    
211
        /**
212
         * The tab panel that occupies the right side of the screen.
213
         */
214
        private VerticalPanel inner = new VerticalPanel();
215

    
216

    
217
        /**
218
         * The split panel that will contain the left and right panels.
219
         */
220
        private HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
221

    
222
        /**
223
         * The currently selected item in the application, for use by the Edit menu
224
         * commands. Potential types are Folder, File, User and Group.
225
         */
226
        private Object currentSelection;
227

    
228

    
229
        /**
230
         * The WebDAV password of the current user
231
         */
232
        private String webDAVPassword;
233

    
234
        public HashMap<String, String> userFullNameMap = new HashMap<String, String>();
235

    
236
    private String username = null;
237

    
238
    /**
239
     * The authentication token of the current user.
240
     */
241
    private String token;
242

    
243
    protected SingleSelectionModel<Folder> folderTreeSelectionModel;
244
    protected FolderTreeViewModel folderTreeViewModel;
245
    protected FolderTreeView folderTreeView;
246

    
247
    protected SingleSelectionModel<Folder> mysharedTreeSelectionModel;
248
    private MysharedTreeViewModel mysharedTreeViewModel;
249
    private MysharedTreeView mysharedTreeView;
250

    
251
    protected SingleSelectionModel<Folder> otherSharedTreeSelectionModel;
252
    private OtherSharedTreeViewModel otherSharedTreeViewModel;
253
    private OtherSharedTreeView otherSharedTreeView;
254

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

    
259
    private GroupTreeViewModel groupTreeViewModel;
260
    private GroupTreeView groupTreeView;
261

    
262
    protected AccountResource account;
263
    
264
    private Folder trash;
265

    
266
    @SuppressWarnings("rawtypes")
267
        private List<SingleSelectionModel> selectionModels = new ArrayList<SingleSelectionModel>();
268

    
269
        @Override
270
        public void onModuleLoad() {
271
                if (parseUserCredentials())
272
            initialize();
273
        }
274

    
275
    private void initialize() {
276
        VerticalPanel outer = new VerticalPanel();
277
        outer.setWidth("100%");
278

    
279
        topPanel = new TopPanel(this, Pithos.images);
280
        topPanel.setWidth("100%");
281
        outer.add(topPanel);
282

    
283
        messagePanel.setWidth("100%");
284
        messagePanel.setVisible(false);
285
        outer.add(messagePanel);
286
        outer.setCellHorizontalAlignment(messagePanel, HasHorizontalAlignment.ALIGN_CENTER);
287

    
288

    
289
        // Inner contains the various lists.
290
        inner.sinkEvents(Event.ONCONTEXTMENU);
291
        inner.setWidth("100%");
292

    
293
        HorizontalPanel rightside = new HorizontalPanel();
294
        rightside.addStyleName("pithos-rightSide");
295
        rightside.setSpacing(5);
296

    
297
        PushButton parentButton = new PushButton(new Image(images.asc()), new ClickHandler() {
298
            @Override
299
            public void onClick(@SuppressWarnings("unused") ClickEvent event) {
300

    
301
            }
302
        });
303
        parentButton.addStyleName("pithos-parentButton");
304
        rightside.add(parentButton);
305

    
306
        HTML folderStatistics = new HTML("5 Files (size: 1.1GB)");
307
        folderStatistics.addStyleName("pithos-folderStatistics");
308
        rightside.add(folderStatistics);
309
        inner.add(rightside);
310
        inner.setCellHorizontalAlignment(rightside, HasHorizontalAlignment.ALIGN_RIGHT);
311
        inner.setCellVerticalAlignment(rightside, HasVerticalAlignment.ALIGN_MIDDLE);
312
        inner.setCellHeight(rightside, "60px");
313

    
314
        folderTreeSelectionModel = new SingleSelectionModel<Folder>();
315
        folderTreeSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
316
            @Override
317
            public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
318
                if (folderTreeSelectionModel.getSelectedObject() != null) {
319
                    deselectOthers(folderTreeSelectionModel);
320
                    Folder f = folderTreeSelectionModel.getSelectedObject();
321
                    updateFolder(f, true, null);
322
                }
323
            }
324
        });
325
        selectionModels.add(folderTreeSelectionModel);
326

    
327
        folderTreeViewModel = new FolderTreeViewModel(this, folderTreeSelectionModel);
328
        folderTreeView = new FolderTreeView(folderTreeViewModel);
329

    
330
        fileList = new FileList(this, images, folderTreeView);
331
        inner.add(fileList);
332

    
333
        mysharedTreeSelectionModel = new SingleSelectionModel<Folder>();
334
        mysharedTreeSelectionModel.addSelectionChangeHandler(new Handler() {
335
            @Override
336
            public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
337
                if (mysharedTreeSelectionModel.getSelectedObject() != null) {
338
                    deselectOthers(mysharedTreeSelectionModel);
339
                    updateSharedFolder(mysharedTreeSelectionModel.getSelectedObject(), true);
340
                }
341
            }
342
        });
343
        selectionModels.add(mysharedTreeSelectionModel);
344
        mysharedTreeViewModel = new MysharedTreeViewModel(this, mysharedTreeSelectionModel);
345
        mysharedTreeView = new MysharedTreeView(mysharedTreeViewModel);
346

    
347
        otherSharedTreeSelectionModel = new SingleSelectionModel<Folder>();
348
        otherSharedTreeSelectionModel.addSelectionChangeHandler(new Handler() {
349
            @Override
350
            public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
351
                if (otherSharedTreeSelectionModel.getSelectedObject() != null) {
352
                    deselectOthers(otherSharedTreeSelectionModel);
353
                    updateOtherSharedFolder(otherSharedTreeSelectionModel.getSelectedObject(), true);
354
                }
355
            }
356
        });
357
        selectionModels.add(otherSharedTreeSelectionModel);
358
        otherSharedTreeViewModel = new OtherSharedTreeViewModel(this, otherSharedTreeSelectionModel);
359
        otherSharedTreeView = new OtherSharedTreeView(otherSharedTreeViewModel);
360

    
361
        tagTreeSelectionModel = new SingleSelectionModel<Tag>();
362
        tagTreeSelectionModel.addSelectionChangeHandler(new Handler() {
363
            @Override
364
            public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
365
                if (tagTreeSelectionModel.getSelectedObject() != null) {
366
                    deselectOthers(tagTreeSelectionModel);
367
                    Tag t = tagTreeSelectionModel.getSelectedObject();
368
                    updateTag(t);
369
                }
370
            }
371
        });
372
        selectionModels.add(tagTreeSelectionModel);
373
        tagTreeViewModel = new TagTreeViewModel(this, tagTreeSelectionModel);
374
        tagTreeView = new TagTreeView(tagTreeViewModel);
375

    
376
        groupTreeViewModel = new GroupTreeViewModel(this);
377
        groupTreeView = new GroupTreeView(groupTreeViewModel);
378

    
379
        VerticalPanel trees = new VerticalPanel();
380

    
381
        Button upload = new Button("Upload File", new ClickHandler() {
382
            @Override
383
            public void onClick(@SuppressWarnings("unused") ClickEvent event) {
384
                new UploadFileCommand(Pithos.this, null, folderTreeView.getSelection()).execute();
385
            }
386
        });
387
        upload.addStyleName("pithos-uploadButton");
388
        trees.add(upload);
389
        
390
        HorizontalPanel treeHeader = new HorizontalPanel();
391
        treeHeader.addStyleName("pithos-treeHeader");
392
        treeHeader.add(new HTML("Total Files: 6 | Used: 2.1 of 50 GB (4.2%)"));
393
        trees.add(treeHeader);
394

    
395
        trees.add(folderTreeView);
396
        trees.add(mysharedTreeView);
397
        trees.add(otherSharedTreeView);
398
//        trees.add(tagTreeView);
399
        trees.add(groupTreeView);
400
        // Add the left and right panels to the split panel.
401
        splitPanel.setLeftWidget(trees);
402
        splitPanel.setRightWidget(inner);
403
        splitPanel.setSplitPosition("25%");
404
        splitPanel.setSize("100%", "100%");
405
        splitPanel.addStyleName("pithos-splitPanel");
406
        outer.add(splitPanel);
407

    
408
        statusPanel = new StatusPanel();
409
        outer.add(statusPanel);
410

    
411

    
412
        // Hook the window resize event, so that we can adjust the UI.
413
        Window.addResizeHandler(this);
414
        // Clear out the window's built-in margin, because we want to take
415
        // advantage of the entire client area.
416
        Window.setMargin("0px");
417
        // Finally, add the outer panel to the RootPanel, so that it will be
418
        // displayed.
419
        RootPanel.get().add(outer);
420
        // Call the window resized handler to get the initial sizes setup. Doing
421
        // this in a deferred command causes it to occur after all widgets'
422
        // sizes have been computed by the browser.
423
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
424

    
425
            @Override
426
            public void execute() {
427
                onWindowResized(Window.getClientHeight());
428
            }
429
        });
430

    
431
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
432
            @Override
433
            public void execute() {
434
                fetchAccount();
435
            }
436
        });
437
    }
438

    
439
    @SuppressWarnings({ "rawtypes", "unchecked" })
440
        public void deselectOthers(SingleSelectionModel model) {
441
        for (SingleSelectionModel s : selectionModels)
442
            if (!s.equals(model))
443
                s.setSelected(s.getSelectedObject(), false);
444
    }
445

    
446
    public void showFiles(Folder f) {
447
        Set<File> files = f.getFiles();
448
        showFiles(files);
449
    }
450

    
451
    public void showFiles(Set<File> files) {
452
        //Iterator<File> iter = files.iterator();
453
        //fetchFile(iter, files);
454
        fileList.setFiles(new ArrayList<File>(files));
455
    }
456

    
457
    protected void fetchFile(final Iterator<File> iter, final Set<File> files) {
458
        if (iter.hasNext()) {
459
            File file = iter.next();
460
            String path = file.getUri() + "?format=json";
461
            GetRequest<File> getFile = new GetRequest<File>(File.class, getApiPath(), username, path, file) {
462
                @Override
463
                public void onSuccess(@SuppressWarnings("unused") File _result) {
464
                    fetchFile(iter, files);
465
                }
466

    
467
                @Override
468
                public void onError(Throwable t) {
469
                    GWT.log("Error getting file", t);
470
                    if (t instanceof RestException)
471
                        displayError("Error getting file: " + ((RestException) t).getHttpStatusText());
472
                    else
473
                        displayError("System error fetching file: " + t.getMessage());
474
                }
475
            };
476
            getFile.setHeader("X-Auth-Token", "0000");
477
            Scheduler.get().scheduleDeferred(getFile);
478
        }
479
        else
480
            fileList.setFiles(new ArrayList<File>(files));
481
    }
482

    
483
    /**
484
         * Parse and store the user credentials to the appropriate fields.
485
         */
486
        private boolean parseUserCredentials() {
487
        username = Window.Location.getParameter("user");
488
        token = Window.Location.getParameter("token");
489
        Configuration conf = (Configuration) GWT.create(Configuration.class);
490
        if (username == null || username.length() == 0 || token == null || token.length() == 0) {
491
            String cookie = conf.authCookie();
492
            String auth = Cookies.getCookie(cookie);
493
            if (auth == null) {
494
                authenticateUser();
495
                return false;
496
            }
497
                        String[] authSplit = auth.split("\\" + conf.cookieSeparator(), 2);
498
                        if (authSplit.length != 2) {
499
                            authenticateUser();
500
                            return false;
501
                        }
502
                        username = authSplit[0];
503
                        token = authSplit[1];
504
                        return true;
505
        }
506
                Cookies.setCookie(conf.authCookie(), username + conf.cookieSeparator() + token);
507
                return true;
508
    }
509

    
510
    /**
511
         * Redirect the user to the login page for authentication.
512
         */
513
        protected void authenticateUser() {
514
                Configuration conf = (Configuration) GWT.create(Configuration.class);
515
        Window.Location.assign(Window.Location.getHost() + conf.loginUrl() + "?next=" + Window.Location.getHref());
516
        }
517

    
518
        protected void fetchAccount() {
519
        String path = "?format=json";
520

    
521
        GetRequest<AccountResource> getAccount = new GetRequest<AccountResource>(AccountResource.class, getApiPath(), username, path) {
522
            @Override
523
            public void onSuccess(AccountResource _result) {
524
                account = _result;
525
                if (!account.hasHomeContainer())
526
                    createHomeContainer(account);
527
                else if (!account.hasTrashContainer())
528
                        createTrashContainer();
529
                else {
530
                        for (Folder f : account.getContainers())
531
                                if (f.getName().equals(Pithos.TRASH_CONTAINER)) {
532
                                        trash = f;
533
                                        break;
534
                                }
535
                    folderTreeViewModel.initialize(account);
536
                    groupTreeViewModel.initialize();
537
                }
538
            }
539

    
540
            @Override
541
            public void onError(Throwable t) {
542
                GWT.log("Error getting account", t);
543
                if (t instanceof RestException)
544
                    displayError("Error getting account: " + ((RestException) t).getHttpStatusText());
545
                else
546
                    displayError("System error fetching user data: " + t.getMessage());
547
            }
548
        };
549
        getAccount.setHeader("X-Auth-Token", token);
550
        Scheduler.get().scheduleDeferred(getAccount);
551
    }
552

    
553
    protected void createHomeContainer(final AccountResource account) {
554
        String path = "/" + Pithos.HOME_CONTAINER;
555
        PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
556
            @Override
557
            public void onSuccess(@SuppressWarnings("unused") Resource result) {
558
                    if (!account.hasTrashContainer())
559
                            createTrashContainer();
560
                    else
561
                            fetchAccount();
562
            }
563

    
564
            @Override
565
            public void onError(Throwable t) {
566
                GWT.log("Error creating pithos", t);
567
                if (t instanceof RestException)
568
                    displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText());
569
                else
570
                    displayError("System error Error creating pithos: " + t.getMessage());
571
            }
572
        };
573
        createPithos.setHeader("X-Auth-Token", getToken());
574
        Scheduler.get().scheduleDeferred(createPithos);
575
    }
576

    
577
    protected void createTrashContainer() {
578
        String path = "/" + Pithos.TRASH_CONTAINER;
579
        PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
580
            @Override
581
            public void onSuccess(@SuppressWarnings("unused") Resource result) {
582
                           fetchAccount();
583
            }
584

    
585
            @Override
586
            public void onError(Throwable t) {
587
                GWT.log("Error creating pithos", t);
588
                if (t instanceof RestException)
589
                    displayError("Error creating pithos: " + ((RestException) t).getHttpStatusText());
590
                else
591
                    displayError("System error Error creating pithos: " + t.getMessage());
592
            }
593
        };
594
        createPithos.setHeader("X-Auth-Token", getToken());
595
        Scheduler.get().scheduleDeferred(createPithos);
596
    }
597

    
598
    /**
599
         * Creates an HTML fragment that places an image & caption together, for use
600
         * in a group header.
601
         *
602
         * @param imageProto an image prototype for an image
603
         * @param caption the group caption
604
         * @return the header HTML fragment
605
         */
606
        private String createHeaderHTML(AbstractImagePrototype imageProto, String caption) {
607
                String captionHTML = "<table class='caption' cellpadding='0' " 
608
                + "cellspacing='0'>" + "<tr><td class='lcaption'>" + imageProto.getHTML() 
609
                + "</td><td id =" + caption +" class='rcaption'><b style='white-space:nowrap'>&nbsp;" 
610
                + caption + "</b></td></tr></table>";
611
                return captionHTML;
612
        }
613

    
614
        protected void onWindowResized(int height) {
615
                // Adjust the split panel to take up the available room in the window.
616
                int newHeight = height - splitPanel.getAbsoluteTop() - 60;
617
                if (newHeight < 1)
618
                        newHeight = 1;
619
                splitPanel.setHeight("" + newHeight);
620
                inner.setHeight("" + newHeight);
621
        }
622

    
623
        @Override
624
        public void onResize(ResizeEvent event) {
625
                int height = event.getHeight();
626
                onWindowResized(height);
627
        }
628

    
629
        /**
630
         * Display an error message.
631
         *
632
         * @param msg the message to display
633
         */
634
        public void displayError(String msg) {
635
                messagePanel.displayError(msg);
636
        }
637

    
638
        /**
639
         * Display a warning message.
640
         *
641
         * @param msg the message to display
642
         */
643
        public void displayWarning(String msg) {
644
                messagePanel.displayWarning(msg);
645
        }
646

    
647
        /**
648
         * Display an informational message.
649
         *
650
         * @param msg the message to display
651
         */
652
        public void displayInformation(String msg) {
653
                messagePanel.displayInformation(msg);
654
        }
655

    
656
        /**
657
         * Retrieve the fileList.
658
         *
659
         * @return the fileList
660
         */
661
        public FileList getFileList() {
662
                return fileList;
663
        }
664

    
665
        /**
666
         * Retrieve the topPanel.
667
         *
668
         * @return the topPanel
669
         */
670
        TopPanel getTopPanel() {
671
                return topPanel;
672
        }
673

    
674
        /**
675
         * Retrieve the clipboard.
676
         *
677
         * @return the clipboard
678
         */
679
        public Clipboard getClipboard() {
680
                return clipboard;
681
        }
682

    
683
        public StatusPanel getStatusPanel() {
684
                return statusPanel;
685
        }
686

    
687
        public String getToken() {
688
                return token;
689
        }
690

    
691
        public String getWebDAVPassword() {
692
                return webDAVPassword;
693
        }
694

    
695
        public static native void preventIESelection() /*-{
696
                $doc.body.onselectstart = function () { return false; };
697
        }-*/;
698

    
699
        public static native void enableIESelection() /*-{
700
                if ($doc.body.onselectstart != null)
701
                $doc.body.onselectstart = null;
702
        }-*/;
703

    
704
        /**
705
         * @return the absolute path of the API root URL
706
         */
707
        public String getApiPath() {
708
                Configuration conf = (Configuration) GWT.create(Configuration.class);
709
                return conf.apiPath();
710
        }
711

    
712
        /**
713
         * History support for folder navigation
714
         * adds a new browser history entry
715
         *
716
         * @param key
717
         */
718
        public void updateHistory(String key){
719
//                Replace any whitespace of the initial string to "+"
720
//                String result = key.replaceAll("\\s","+");
721
//                Add a new browser history entry.
722
//                History.newItem(result);
723
                History.newItem(key);
724
        }
725

    
726
    public void deleteFolder(final Folder folder) {
727
        String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + folder.getPrefix();
728
        RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
729
        builder.setHeader("If-Modified-Since", "0");
730
        builder.setHeader("X-Auth-Token", getToken());
731
        try {
732
            builder.sendRequest("", new RequestCallback() {
733
                @Override
734
                public void onResponseReceived(@SuppressWarnings("unused") Request request, Response response) {
735
                    if (response.getStatusCode() == Response.SC_OK) {
736
                        JSONValue json = JSONParser.parseStrict(response.getText());
737
                        JSONArray array = json.isArray();
738
                        int i = 0;
739
                        if (array != null) {
740
                            deleteObject(folder, i, array);
741
                        }
742
                    }
743
                }
744

    
745
                @Override
746
                public void onError(@SuppressWarnings("unused") Request request, Throwable exception) {
747
                    displayError("System error unable to delete folder: " + exception.getMessage());
748
                }
749
            });
750
        }
751
        catch (RequestException e) {
752
        }
753
    }
754

    
755
    public void deleteObject(final Folder folder, final int i, final JSONArray array) {
756
        if (i < array.size()) {
757
            JSONObject o = array.get(i).isObject();
758
            if (o != null && !o.containsKey("subdir")) {
759
                JSONString name = o.get("name").isString();
760
                String path = "/" + folder.getContainer() + "/" + name.stringValue();
761
                DeleteRequest delete = new DeleteRequest(getApiPath(), getUsername(), path) {
762
                    @Override
763
                    public void onSuccess(@SuppressWarnings("unused") Resource result) {
764
                        deleteObject(folder, i + 1, array);
765
                    }
766

    
767
                    @Override
768
                    public void onError(Throwable t) {
769
                        GWT.log("", t);
770
                        displayError("System error unable to delete folder: " + t.getMessage());
771
                    }
772
                };
773
                delete.setHeader("X-Auth-Token", getToken());
774
                Scheduler.get().scheduleDeferred(delete);
775
            }
776
            else if (o != null) {
777
                String subdir = o.get("subdir").isString().stringValue();
778
                subdir = subdir.substring(0, subdir.length() - 1);
779
                String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + subdir;
780
                RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
781
                builder.setHeader("If-Modified-Since", "0");
782
                builder.setHeader("X-Auth-Token", getToken());
783
                try {
784
                    builder.sendRequest("", new RequestCallback() {
785
                        @Override
786
                        public void onResponseReceived(@SuppressWarnings("unused") Request request, Response response) {
787
                            if (response.getStatusCode() == Response.SC_OK) {
788
                                JSONValue json = JSONParser.parseStrict(response.getText());
789
                                JSONArray array2 = json.isArray();
790
                                if (array2 != null) {
791
                                    int l = array.size();
792
                                    for (int j=0; j<array2.size(); j++) {
793
                                        array.set(l++, array2.get(j));
794
                                    }
795
                                }
796
                                deleteObject(folder, i + 1, array);
797
                            }
798
                        }
799

    
800
                        @Override
801
                        public void onError(@SuppressWarnings("unused") Request request, Throwable exception) {
802
                            displayError("System error unable to delete folder: " + exception.getMessage());
803
                        }
804
                    });
805
                }
806
                catch (RequestException e) {
807
                }
808
            }
809
        }
810
        else {
811
            String path = folder.getUri();
812
            DeleteRequest deleteFolder = new DeleteRequest(getApiPath(), getUsername(), path) {
813
                @Override
814
                public void onSuccess(@SuppressWarnings("unused") Resource result) {
815
                    updateFolder(folder.getParent(), true, null);
816
                }
817

    
818
                @Override
819
                public void onError(Throwable t) {
820
                    GWT.log("", t);
821
                    if (t instanceof RestException) {
822
                            if (((RestException) t).getHttpStatusCode() != Response.SC_NOT_FOUND)
823
                                    displayError("Unable to delete folder: "+((RestException) t).getHttpStatusText());
824
                            else
825
                                    onSuccess(null);
826
                    }
827
                    else
828
                        displayError("System error unable to delete folder: " + t.getMessage());
829
                }
830
            };
831
            deleteFolder.setHeader("X-Auth-Token", getToken());
832
            Scheduler.get().scheduleDeferred(deleteFolder);
833
        }
834
    }
835

    
836
    public FolderTreeView getFolderTreeView() {
837
        return folderTreeView;
838
    }
839

    
840
    public void copyFiles(final Iterator<File> iter, final String targetUri, final Command callback) {
841
        if (iter.hasNext()) {
842
            File file = iter.next();
843
            String path = targetUri + "/" + file.getName();
844
            PutRequest copyFile = new PutRequest(getApiPath(), getUsername(), path) {
845
                @Override
846
                public void onSuccess(@SuppressWarnings("unused") Resource result) {
847
                    copyFiles(iter, targetUri, callback);
848
                }
849

    
850
                @Override
851
                public void onError(Throwable t) {
852
                    GWT.log("", t);
853
                    if (t instanceof RestException) {
854
                        displayError("Unable to copy file: " + ((RestException) t).getHttpStatusText());
855
                    }
856
                    else
857
                        displayError("System error unable to copy file: "+t.getMessage());
858
                }
859
            };
860
            copyFile.setHeader("X-Auth-Token", getToken());
861
            copyFile.setHeader("X-Copy-From", file.getUri());
862
            Scheduler.get().scheduleDeferred(copyFile);
863
        }
864
        else  if (callback != null) {
865
            callback.execute();
866
        }
867
    }
868

    
869
    public void copySubfolders(final Iterator<Folder> iter, final String targetUri, final Command callback) {
870
        if (iter.hasNext()) {
871
            final Folder f = iter.next();
872
            copyFolder(f, targetUri, callback);
873
        }
874
        else  if (callback != null) {
875
            callback.execute();
876
        }
877
    }
878

    
879
    public void copyFolder(final Folder f, final String targetUri, final Command callback) {
880
        String path = targetUri + "/" + f.getName();
881
        PutRequest createFolder = new PutRequest(getApiPath(), getUsername(), path) {
882
            @Override
883
            public void onSuccess(@SuppressWarnings("unused") Resource result) {
884
                Iterator<File> iter = f.getFiles().iterator();
885
                copyFiles(iter, targetUri + "/" + f.getName(), new Command() {
886
                    @Override
887
                    public void execute() {
888
                        Iterator<Folder> iterf = f.getSubfolders().iterator();
889
                        copySubfolders(iterf, targetUri + "/" + f.getName(), new Command() {
890
                            @Override
891
                            public void execute() {
892
                                callback.execute();
893
                            }
894
                        });
895
                    }
896
                });
897
            }
898

    
899
            @Override
900
            public void onError(Throwable t) {
901
                GWT.log("", t);
902
                if (t instanceof RestException) {
903
                    displayError("Unable to create folder:" + ((RestException) t).getHttpStatusText());
904
                }
905
                else
906
                    displayError("System error creating folder:" + t.getMessage());
907
            }
908
        };
909
        createFolder.setHeader("X-Auth-Token", getToken());
910
        createFolder.setHeader("Accept", "*/*");
911
        createFolder.setHeader("Content-Length", "0");
912
        createFolder.setHeader("Content-Type", "application/folder");
913
        Scheduler.get().scheduleDeferred(createFolder);
914
    }
915
    
916
    public void addSelectionModel(@SuppressWarnings("rawtypes") SingleSelectionModel model) {
917
            selectionModels.add(model);
918
    }
919

    
920
        public OtherSharedTreeView getOtherSharedTreeView() {
921
                return otherSharedTreeView;
922
        }
923

    
924
        public void updateTrash(boolean showFiles, Command callback) {
925
                updateFolder(trash, showFiles, callback);
926
        }
927

    
928
        public void updateGroupsNode() {
929
                groupTreeView.updateGroupNode(null);
930
        }
931

    
932
        public void addGroup(String groupname) {
933
                Group newGroup = new Group(groupname);
934
                account.addGroup(newGroup);
935
                groupTreeView.updateGroupNode(null);
936
        }
937

    
938
        public void removeGroup(Group group) {
939
                account.removeGroup(group);
940
                updateGroupsNode();
941
        }
942
}