Statistics
| Branch: | Tag: | Revision:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
215

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

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

    
227

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

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

    
235
    private String username = null;
236

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

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

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

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

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

    
258
    private GroupTreeViewModel groupTreeViewModel;
259
    private GroupTreeView groupTreeView;
260

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

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

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

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

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

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

    
287

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

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

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

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

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

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

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

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

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

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

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

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

    
378
        VerticalPanel trees = new VerticalPanel();
379

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

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

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

    
410

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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