Statistics
| Branch: | Tag: | Revision:

root / web_client / src / gr / grnet / pithos / web / client / FolderPropertiesDialog.java @ ef3dd275

History | View | Annotate | Download (18.6 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.event.dom.client.KeyDownEvent;
39
import com.google.gwt.user.client.Command;
40
import gr.grnet.pithos.web.client.foldertree.File;
41
import gr.grnet.pithos.web.client.foldertree.Folder;
42
import gr.grnet.pithos.web.client.foldertree.Resource;
43
import gr.grnet.pithos.web.client.rest.PostRequest;
44
import gr.grnet.pithos.web.client.rest.PutRequest;
45
import gr.grnet.pithos.web.client.rest.RestException;
46

    
47
import com.google.gwt.core.client.GWT;
48
import com.google.gwt.dom.client.NativeEvent;
49
import com.google.gwt.event.dom.client.ChangeEvent;
50
import com.google.gwt.event.dom.client.ChangeHandler;
51
import com.google.gwt.event.dom.client.ClickEvent;
52
import com.google.gwt.event.dom.client.ClickHandler;
53
import com.google.gwt.event.dom.client.KeyCodes;
54
import com.google.gwt.http.client.Response;
55
import com.google.gwt.i18n.client.DateTimeFormat;
56
import com.google.gwt.user.client.Event.NativePreviewEvent;
57
import com.google.gwt.user.client.ui.Anchor;
58
import com.google.gwt.user.client.ui.Button;
59
import com.google.gwt.user.client.ui.DecoratedTabPanel;
60
import com.google.gwt.user.client.ui.DialogBox;
61
import com.google.gwt.user.client.ui.FlexTable;
62
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
63
import com.google.gwt.user.client.ui.HorizontalPanel;
64
import com.google.gwt.user.client.ui.Label;
65
import com.google.gwt.user.client.ui.TabPanel;
66
import com.google.gwt.user.client.ui.TextBox;
67
import com.google.gwt.user.client.ui.VerticalPanel;
68
import java.util.Iterator;
69
import java.util.Map;
70

    
71
/**
72
 * The 'Folder properties' dialog box implementation.
73
 */
74
public class FolderPropertiesDialog extends DialogBox {
75

    
76
    protected Pithos app;
77

    
78
        /**
79
         * The widget that holds the folderName of the folder.
80
         */
81
        TextBox folderName = new TextBox();
82

    
83
        /**
84
         * A flag that denotes whether the dialog will be used to create or modify a
85
         * folder.
86
         */
87
        private final boolean create;
88

    
89
        protected PermissionsList permList;
90

    
91
        final Folder folder;
92

    
93
        final TabPanel inner;
94

    
95
        /**
96
         * The widget's constructor.
97
         */
98
        public FolderPropertiesDialog(final Pithos app, boolean _create,  Folder selected) {
99
        this.app = app;
100
                Anchor close = new Anchor();
101
                close.addStyleName("close");
102
                close.addClickHandler(new ClickHandler() {
103
                        
104
                        @Override
105
                        public void onClick(ClickEvent event) {
106
                                hide();
107
                        }
108
                });
109

    
110
                setAnimationEnabled(true);
111
                setGlassEnabled(true);
112
                setStyleName("pithos-DialogBox");
113

    
114
                // Enable IE selection for the dialog (must disable it upon closing it)
115
                Pithos.enableIESelection();
116

    
117
                create = _create;
118
                
119
                folder = selected;
120

    
121
                // Use this opportunity to set the dialog's caption.
122
                if (create)
123
                        setText("Create folder");
124
                else
125
                        setText("Folder properties");
126

    
127
                // Outer contains inner and buttons
128
                VerticalPanel outer = new VerticalPanel();
129
                outer.add(close);
130
                // Inner contains generalPanel and permPanel
131
                inner = new DecoratedTabPanel();
132
                inner.setAnimationEnabled(true);
133
                inner.addStyleName("inner");
134
                inner.getDeckPanel().addStyleName("pithos-TabPanelBottom");
135

    
136
                VerticalPanel generalPanel = new VerticalPanel();
137
        FlexTable generalTable = new FlexTable();
138
        generalTable.setText(0, 0, "Name");
139
        generalTable.setText(1, 0, "Parent");
140
        generalTable.setText(2, 0, "Creator");
141
        generalTable.setText(3, 0, "Last modified");
142

    
143
                folderName.setText(create ? "" : folder.getName());
144
        folderName.setReadOnly(folder.isContainer() && !create);
145
        generalTable.setWidget(0, 1, folderName);
146

    
147
        final Label folderNameNote = new Label("Please note that slashes ('/') are not allowed in folder names.", true);
148
                folderNameNote.setVisible(false);
149
                folderNameNote.setStylePrimaryName("gss-readForAllNote");
150
                generalTable.setWidget(0, 2, folderNameNote);
151
                
152
        if (create)
153
            generalTable.setText(1, 1, folder.getName());
154
        else
155
            generalTable.setText(1, 1, folder.getPrefix());
156
        generalTable.setText(2, 1, "");
157
        DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
158
        if(folder.getLastModified() != null)
159
            generalTable.setText(3, 1, formatter.format(folder.getLastModified()));
160
        generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");
161
        generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");
162
        generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");
163
        generalTable.getFlexCellFormatter().setStyleName(3, 0, "props-labels");
164
        generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");
165
        generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");
166
        generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");
167
        generalTable.getFlexCellFormatter().setStyleName(3, 1, "props-values");
168
        generalTable.setCellSpacing(4);
169
        generalPanel.add(generalTable);
170
        inner.add(generalPanel, "General");
171

    
172
        VerticalPanel permPanel = new VerticalPanel();
173
        FilePropertiesDialog.Images images = GWT.create(FilePropertiesDialog.Images.class);
174
        boolean permsReadonly = folder.getInheritedPermissionsFrom() != null || folder.existChildrenPermissions();
175
        permList = new PermissionsList(images, folder.getPermissions(), folder.getOwner(), permsReadonly);
176
        permPanel.add(permList);
177

    
178
        if (!permsReadonly) {
179
            HorizontalPanel permButtons = new HorizontalPanel();
180
            Button add = new Button("Add Group", new ClickHandler() {
181
                @Override
182
                public void onClick(@SuppressWarnings("unused") ClickEvent event) {
183
                    PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, false);
184
                    dlg.center();
185
                }
186
            });
187
            add.addStyleName("button");
188
            permButtons.add(add);
189
            permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);
190

    
191
            Button addUser = new Button("Add User", new ClickHandler() {
192
                @Override
193
                public void onClick(@SuppressWarnings("unused") ClickEvent event) {
194
                    PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, true);
195
                    dlg.center();
196
                }
197
            });
198
            addUser.addStyleName("button");
199
            permButtons.add(addUser);
200
            permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);
201
            permButtons.setSpacing(8);
202
            permPanel.add(permButtons);
203
        }
204

    
205
        if (!create)
206
            inner.add(permPanel, "Sharing");
207
        inner.selectTab(0);
208

    
209
        outer.add(inner);
210

    
211
                // Create the 'Create/Update' button, along with a listener that hides the dialog
212
                // when the button is clicked and quits the application.
213
                String okLabel;
214
                if (create)
215
                        okLabel = "Create";
216
                else
217
                        okLabel = "Update";
218
                final Button ok = new Button(okLabel, new ClickHandler() {
219
                        @Override
220
                        public void onClick(@SuppressWarnings("unused") ClickEvent event) {
221
                                createOrUpdateFolder();
222
                                closeDialog();
223
                        }
224
                });
225
                ok.addStyleName("button");
226
                outer.add(ok);
227
        outer.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);
228

    
229
        folderName.addChangeHandler(new ChangeHandler() {
230
                        
231
                        @Override
232
                        public void onChange(@SuppressWarnings("unused") ChangeEvent event) {
233
                                if(folderName.getText().contains("/")) {
234
                                        folderNameNote.setVisible(true);
235
                                        ok.setEnabled(false);
236
                                }
237
                                else {
238
                                        folderNameNote.setVisible(false);
239
                                        ok.setEnabled(true);
240
                                }
241
                        }
242
                });
243

    
244
        setWidget(outer);
245
        }
246

    
247
        @Override
248
        public void center() {
249
                super.center();
250
                folderName.setFocus(true);
251
        }
252

    
253
        @Override
254
        protected void onPreviewNativeEvent(NativePreviewEvent preview) {
255
                super.onPreviewNativeEvent(preview);
256

    
257
                NativeEvent evt = preview.getNativeEvent();
258
                if (evt.getType().equals(KeyDownEvent.getType().getName()))
259
                        // Use the popup's key preview hooks to close the dialog when either
260
                        // enter or escape is pressed.
261
                        switch (evt.getKeyCode()) {
262
                                case KeyCodes.KEY_ENTER:
263
                                        createOrUpdateFolder();
264
                    closeDialog();
265
                                        break;
266
                                case KeyCodes.KEY_ESCAPE:
267
                                        closeDialog();
268
                                        break;
269
                        }
270
        }
271

    
272

    
273
        /**
274
         * Enables IE selection prevention and hides the dialog
275
         * (we disable the prevention on creation of the dialog)
276
         */
277
        public void closeDialog() {
278
                Pithos.preventIESelection();
279
                hide();
280
        }
281

    
282
        /**
283
         * Generate an RPC request to create a new folder.
284
         */
285
        private void createFolder() {
286
                String name = folderName.getText().trim();
287
        String path = folder.getUri() + "/" + name;
288
        PutRequest createFolder = new PutRequest(app.getApiPath(), folder.getOwner(), path) {
289
            @Override
290
            public void onSuccess(@SuppressWarnings("unused") Resource result) {
291
                app.updateFolder(folder, true, new Command() {
292
                                        
293
                                        @Override
294
                                        public void execute() {
295
                                                app.updateStatistics();
296
                                        }
297
                                });
298
            }
299

    
300
            @Override
301
            public void onError(Throwable t) {
302
                                GWT.log("", t);
303
                                if (t instanceof RestException) {
304
                                        app.displayError("Unable to create folder:" + ((RestException) t).getHttpStatusText());
305
                                }
306
                                else
307
                                        app.displayError("System error creating folder:" + t.getMessage());
308
            }
309

    
310
                        @Override
311
                        protected void onUnauthorized(Response response) {
312
                                app.sessionExpired();
313
                        }
314
       };
315
        createFolder.setHeader("X-Auth-Token", app.getToken());
316
        createFolder.setHeader("Accept", "*/*");
317
        createFolder.setHeader("Content-Length", "0");
318
        createFolder.setHeader("Content-Type", "application/directory");
319
        Scheduler.get().scheduleDeferred(createFolder);
320
        }
321

    
322
        /**
323
         * Upon closing the dialog by clicking OK or pressing ENTER this method does
324
         * the actual work of modifying folder properties or creating a new Folder
325
         * depending on the value of the create field
326
         */
327
        protected void createOrUpdateFolder() {
328
                if (create)
329
                        createFolder();
330
                else
331
                        updateFolder();
332

    
333
        }
334

    
335
        private void updateFolder() {
336
        final Map<String, Boolean[]> perms = (permList.hasChanges() ? permList.getPermissions() : null);
337
        final String newName = folderName.getText().trim();
338
        if (!folder.isContainer() && !folder.getName().equals(newName)) {
339
            final String path = folder.getParent().getUri() + "/" + newName;
340
            PutRequest newFolder = new PutRequest(app.getApiPath(), folder.getParent().getOwner(), path) {
341
                @Override
342
                public void onSuccess(@SuppressWarnings("unused") Resource result) {
343
                    Iterator<File> iter = folder.getFiles().iterator();
344
                    app.copyFiles(iter, folder.getParent().getOwner(), folder.getParent().getUri() + "/" + newName, new Command() {
345
                        @Override
346
                        public void execute() {
347
                            Iterator<Folder> iterf = folder.getSubfolders().iterator();
348
                            app.copySubfolders(iterf, folder.getParent().getOwner(), folder.getParent().getUri() + "/" + newName, new Command() {
349
                                @Override
350
                                public void execute() {
351
                                    app.deleteFolder(folder);
352
                                    updateMetadata(path + "?update=", perms);
353
                                }
354
                            });
355
                        }
356
                    });
357
                }
358

    
359
                @Override
360
                public void onError(Throwable t) {
361
                    GWT.log("", t);
362
                    if(t instanceof RestException){
363
                        app.displayError("Unable to update folder: " + ((RestException) t).getHttpStatusText());
364
                    }
365
                    else
366
                        app.displayError("System error modifying folder: " + t.getMessage());
367
                }
368

    
369
                                @Override
370
                                protected void onUnauthorized(Response response) {
371
                                        app.sessionExpired();
372
                                }
373
            };
374
            newFolder.setHeader("X-Auth-Token", app.getToken());
375
            newFolder.setHeader("Content-Type", "application/folder");
376
            newFolder.setHeader("Accept", "*/*");
377
            newFolder.setHeader("Content-Length", "0");
378
            Scheduler.get().scheduleDeferred(newFolder);
379
        }
380
        else
381
            updateMetadata(folder.getUri() + "?update=", perms);
382
        }
383

    
384
        protected void updateMetadata(final String path, final Map<String, Boolean[]> newPermissions) {
385
        if (newPermissions != null) {
386
            PostRequest updateFolder = new PostRequest(app.getApiPath(), folder.getOwner(), path) {
387
                @Override
388
                public void onSuccess(@SuppressWarnings("unused") Resource result) {
389
                    app.updateFolder(folder.getParent(), false, null);
390
                }
391

    
392
                @Override
393
                public void onError(Throwable t) {
394
                    GWT.log("", t);
395
                    if (t instanceof RestException) {
396
                            if (((RestException) t).getHttpStatusCode() == Response.SC_NOT_FOUND) { //Probably a virtual folder
397
                            final String path1 = folder.getUri();
398
                            PutRequest newFolder = new PutRequest(app.getApiPath(), folder.getOwner(), path1) {
399
                                @Override
400
                                public void onSuccess(@SuppressWarnings("unused") Resource result) {
401
                                        updateMetadata(path, newPermissions);
402
                                }
403

    
404
                                @Override
405
                                public void onError(Throwable _t) {
406
                                    GWT.log("", _t);
407
                                    if(_t instanceof RestException){
408
                                        app.displayError("Unable to update folder: " + ((RestException) _t).getHttpStatusText());
409
                                    }
410
                                    else
411
                                        app.displayError("System error modifying folder: " + _t.getMessage());
412
                                }
413

    
414
                                                @Override
415
                                                protected void onUnauthorized(Response response) {
416
                                                        app.sessionExpired();
417
                                                }
418
                            };
419
                            newFolder.setHeader("X-Auth-Token", app.getToken());
420
                            newFolder.setHeader("Content-Type", "application/folder");
421
                            newFolder.setHeader("Accept", "*/*");
422
                            newFolder.setHeader("Content-Length", "0");
423
                            Scheduler.get().scheduleDeferred(newFolder);
424
                            }
425
                            else if (((RestException) t).getHttpStatusCode() == Response.SC_CONFLICT) {
426
                                    app.displayError("Cannot set permissions. Probably subfolders or files already have permissions set");
427
                            }
428
                            else
429
                                    app.displayError("Wrror modifying folder: " + t.getMessage());
430
                    }
431
                    else
432
                            app.displayError("System error modifying folder: " + t.getMessage());
433
                }
434

    
435
                                @Override
436
                                protected void onUnauthorized(Response response) {
437
                                        app.sessionExpired();
438
                                }
439
            };
440
            updateFolder.setHeader("X-Auth-Token", app.getToken());
441
            String readPermHeader = "read=";
442
            String writePermHeader = "write=";
443
            for (String u : newPermissions.keySet()) {
444
                Boolean[] p = newPermissions.get(u);
445
                if (p[0] != null && p[0])
446
                    readPermHeader += u + ",";
447
                if (p[1] != null && p[1])
448
                    writePermHeader += u + ",";
449
            }
450
            if (readPermHeader.endsWith("="))
451
                readPermHeader = "";
452
            else if (readPermHeader.endsWith(","))
453
                readPermHeader = readPermHeader.substring(0, readPermHeader.length() - 1);
454
            if (writePermHeader.endsWith("="))
455
                writePermHeader = "";
456
            else if (writePermHeader.endsWith(","))
457
                writePermHeader = writePermHeader.substring(0, writePermHeader.length() - 1);
458
            String permHeader = readPermHeader +  ((readPermHeader.length()  > 0 && writePermHeader.length() > 0) ?  ";" : "") + writePermHeader;
459
            if (permHeader.length() == 0)
460
                permHeader="~";
461
            updateFolder.setHeader("X-Object-Sharing", permHeader);
462
            Scheduler.get().scheduleDeferred(updateFolder);
463
        }
464
        else
465
            app.updateFolder(folder.getParent(), false, null);
466
    }
467

    
468
        public void selectTab(int _tab) {
469
                inner.selectTab(_tab);
470
        }
471
}