Statistics
| Branch: | Tag: | Revision:

root / src / gr / grnet / pithos / web / client / FolderPropertiesDialog.java @ 9539e23d

History | View | Annotate | Download (17.7 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.ClickEvent;
50
import com.google.gwt.event.dom.client.ClickHandler;
51
import com.google.gwt.event.dom.client.KeyCodes;
52
import com.google.gwt.http.client.Response;
53
import com.google.gwt.i18n.client.DateTimeFormat;
54
import com.google.gwt.user.client.Event.NativePreviewEvent;
55
import com.google.gwt.user.client.ui.Button;
56
import com.google.gwt.user.client.ui.DecoratedTabPanel;
57
import com.google.gwt.user.client.ui.DialogBox;
58
import com.google.gwt.user.client.ui.FlexTable;
59
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
60
import com.google.gwt.user.client.ui.HorizontalPanel;
61
import com.google.gwt.user.client.ui.TabPanel;
62
import com.google.gwt.user.client.ui.TextBox;
63
import com.google.gwt.user.client.ui.VerticalPanel;
64
import java.util.Iterator;
65
import java.util.Map;
66

    
67
/**
68
 * The 'Folder properties' dialog box implementation.
69
 */
70
public class FolderPropertiesDialog extends DialogBox {
71

    
72
    protected Pithos app;
73

    
74
        /**
75
         * The widget that holds the folderName of the folder.
76
         */
77
        private TextBox folderName = new TextBox();
78

    
79
        /**
80
         * A flag that denotes whether the dialog will be used to create or modify a
81
         * folder.
82
         */
83
        private final boolean create;
84

    
85
        protected PermissionsList permList;
86

    
87
        final Folder folder;
88

    
89
        final TabPanel inner;
90

    
91
        /**
92
         * The widget's constructor.
93
         */
94
        public FolderPropertiesDialog(final Pithos app, boolean _create,  Folder selected) {
95
        this.app = app;
96
                setAnimationEnabled(true);
97

    
98
                // Enable IE selection for the dialog (must disable it upon closing it)
99
                Pithos.enableIESelection();
100

    
101
                create = _create;
102
                
103
                folder = selected;
104

    
105
                // Use this opportunity to set the dialog's caption.
106
                if (create)
107
                        setText("Create folder");
108
                else
109
                        setText("Folder properties");
110

    
111
                // Outer contains inner and buttons
112
                VerticalPanel outer = new VerticalPanel();
113
                // Inner contains generalPanel and permPanel
114
                inner = new DecoratedTabPanel();
115
                inner.setAnimationEnabled(true);
116

    
117
                VerticalPanel generalPanel = new VerticalPanel();
118
        FlexTable generalTable = new FlexTable();
119
        generalTable.setText(0, 0, "Name");
120
        generalTable.setText(1, 0, "Parent");
121
        generalTable.setText(2, 0, "Creator");
122
        generalTable.setText(3, 0, "Last modified");
123
        folderName.setText(create ? "" : folder.getName());
124
        folderName.setReadOnly(folder.isContainer() && !create);
125
        generalTable.setWidget(0, 1, folderName);
126

    
127
        if (create)
128
            generalTable.setText(1, 1, folder.getName());
129
        else
130
            generalTable.setText(1, 1, folder.getPrefix());
131
        generalTable.setText(2, 1, "");
132
        DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");
133
        if(folder.getLastModified() != null)
134
            generalTable.setText(3, 1, formatter.format(folder.getLastModified()));
135
        generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");
136
        generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");
137
        generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");
138
        generalTable.getFlexCellFormatter().setStyleName(3, 0, "props-labels");
139
        generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");
140
        generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");
141
        generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");
142
        generalTable.getFlexCellFormatter().setStyleName(3, 1, "props-values");
143
        generalTable.setCellSpacing(4);
144
        generalPanel.add(generalTable);
145
        inner.add(generalPanel, "General");
146

    
147
        VerticalPanel permPanel = new VerticalPanel();
148
        FilePropertiesDialog.Images images = GWT.create(FilePropertiesDialog.Images.class);
149
        boolean permsReadonly = folder.getInheritedPermissionsFrom() != null || folder.existChildrenPermissions();
150
        permList = new PermissionsList(images, folder.getPermissions(), folder.getOwner(), permsReadonly);
151
        permPanel.add(permList);
152

    
153
        if (!permsReadonly) {
154
            HorizontalPanel permButtons = new HorizontalPanel();
155
            Button add = new Button("Add Group", new ClickHandler() {
156
                @Override
157
                public void onClick(@SuppressWarnings("unused") ClickEvent event) {
158
                    PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, false);
159
                    dlg.center();
160
                }
161
            });
162
            permButtons.add(add);
163
            permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);
164

    
165
            Button addUser = new Button("Add User", new ClickHandler() {
166
                @Override
167
                public void onClick(@SuppressWarnings("unused") ClickEvent event) {
168
                    PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, true);
169
                    dlg.center();
170
                }
171
            });
172
            addUser.getElement().setId("folderPropertiesDialog.button.addUser");
173
            permButtons.add(addUser);
174
            permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);
175
            permButtons.setSpacing(8);
176
            permButtons.addStyleName("gss-TabPanelBottom");
177
            permPanel.add(permButtons);
178
        }
179

    
180
        if (!create)
181
            inner.add(permPanel, "Sharing");
182
        inner.selectTab(0);
183

    
184
        outer.add(inner);
185

    
186
        HorizontalPanel buttons = new HorizontalPanel();
187
                // Create the 'Create/Update' button, along with a listener that hides the dialog
188
                // when the button is clicked and quits the application.
189
                String okLabel;
190
                if (create)
191
                        okLabel = "Create";
192
                else
193
                        okLabel = "Update";
194
                Button ok = new Button(okLabel, new ClickHandler() {
195
                        @Override
196
                        public void onClick(@SuppressWarnings("unused") ClickEvent event) {
197
                                createOrUpdateFolder();
198
                                closeDialog();
199
                        }
200
                });
201
                buttons.add(ok);
202
                buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);
203
                // Create the 'Cancel' button, along with a listener that hides the
204
                // dialog
205
                // when the button is clicked.
206
                Button cancel = new Button("Cancel", new ClickHandler() {
207
                        @Override
208
                        public void onClick(@SuppressWarnings("unused") ClickEvent event) {
209
                                closeDialog();
210
                        }
211
                });
212
                buttons.add(cancel);
213
                buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);
214
                buttons.setSpacing(8);
215
                buttons.addStyleName("pithos-TabPanelBottom");
216
        outer.add(buttons);
217
        outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
218
        outer.addStyleName("pithos-TabPanelBottom");
219

    
220
        setWidget(outer);
221
        }
222

    
223
        @Override
224
        public void center() {
225
                super.center();
226
                folderName.setFocus(true);
227
        }
228

    
229
        @Override
230
        protected void onPreviewNativeEvent(NativePreviewEvent preview) {
231
                super.onPreviewNativeEvent(preview);
232

    
233
                NativeEvent evt = preview.getNativeEvent();
234
                if (evt.getType().equals(KeyDownEvent.getType().getName()))
235
                        // Use the popup's key preview hooks to close the dialog when either
236
                        // enter or escape is pressed.
237
                        switch (evt.getKeyCode()) {
238
                                case KeyCodes.KEY_ENTER:
239
                                        createOrUpdateFolder();
240
                    closeDialog();
241
                                        break;
242
                                case KeyCodes.KEY_ESCAPE:
243
                                        closeDialog();
244
                                        break;
245
                        }
246
        }
247

    
248

    
249
        /**
250
         * Enables IE selection prevention and hides the dialog
251
         * (we disable the prevention on creation of the dialog)
252
         */
253
        public void closeDialog() {
254
                Pithos.preventIESelection();
255
                hide();
256
        }
257

    
258
        /**
259
         * Generate an RPC request to create a new folder.
260
         */
261
        private void createFolder() {
262
                String name = folderName.getText();
263
        String path = folder.getUri() + "/" + name;
264
        PutRequest createFolder = new PutRequest(app.getApiPath(), folder.getOwner(), path) {
265
            @Override
266
            public void onSuccess(@SuppressWarnings("unused") Resource result) {
267
                app.updateFolder(folder, true, new Command() {
268
                                        
269
                                        @Override
270
                                        public void execute() {
271
                                                app.updateStatistics();
272
                                        }
273
                                });
274
            }
275

    
276
            @Override
277
            public void onError(Throwable t) {
278
                                GWT.log("", t);
279
                                if (t instanceof RestException) {
280
                                        app.displayError("Unable to create folder:" + ((RestException) t).getHttpStatusText());
281
                                }
282
                                else
283
                                        app.displayError("System error creating folder:" + t.getMessage());
284
            }
285

    
286
                        @Override
287
                        protected void onUnauthorized(Response response) {
288
                                app.sessionExpired();
289
                        }
290
       };
291
        createFolder.setHeader("X-Auth-Token", app.getToken());
292
        createFolder.setHeader("Accept", "*/*");
293
        createFolder.setHeader("Content-Length", "0");
294
        createFolder.setHeader("Content-Type", "application/folder");
295
        Scheduler.get().scheduleDeferred(createFolder);
296
        }
297

    
298
        /**
299
         * Upon closing the dialog by clicking OK or pressing ENTER this method does
300
         * the actual work of modifying folder properties or creating a new Folder
301
         * depending on the value of the create field
302
         */
303
        protected void createOrUpdateFolder() {
304
                if (create)
305
                        createFolder();
306
                else
307
                        updateFolder();
308

    
309
        }
310

    
311
        private void updateFolder() {
312
        final Map<String, Boolean[]> perms = (permList.hasChanges() ? permList.getPermissions() : null);
313
        final String newName = folderName.getText().trim();
314
        if (!folder.isContainer() && !folder.getName().equals(newName)) {
315
            final String path = folder.getParent().getUri() + "/" + newName;
316
            PutRequest newFolder = new PutRequest(app.getApiPath(), folder.getParent().getOwner(), path) {
317
                @Override
318
                public void onSuccess(@SuppressWarnings("unused") Resource result) {
319
                    Iterator<File> iter = folder.getFiles().iterator();
320
                    app.copyFiles(iter, folder.getParent().getOwner(), folder.getParent().getUri() + "/" + newName, new Command() {
321
                        @Override
322
                        public void execute() {
323
                            Iterator<Folder> iterf = folder.getSubfolders().iterator();
324
                            app.copySubfolders(iterf, folder.getParent().getOwner(), folder.getParent().getUri() + "/" + newName, new Command() {
325
                                @Override
326
                                public void execute() {
327
                                    app.deleteFolder(folder);
328
                                    updateMetadata(path + "?update=", perms);
329
                                }
330
                            });
331
                        }
332
                    });
333
                }
334

    
335
                @Override
336
                public void onError(Throwable t) {
337
                    GWT.log("", t);
338
                    if(t instanceof RestException){
339
                        app.displayError("Unable to update folder: " + ((RestException) t).getHttpStatusText());
340
                    }
341
                    else
342
                        app.displayError("System error modifying folder: " + t.getMessage());
343
                }
344

    
345
                                @Override
346
                                protected void onUnauthorized(Response response) {
347
                                        app.sessionExpired();
348
                                }
349
            };
350
            newFolder.setHeader("X-Auth-Token", app.getToken());
351
            newFolder.setHeader("Content-Type", "application/folder");
352
            newFolder.setHeader("Accept", "*/*");
353
            newFolder.setHeader("Content-Length", "0");
354
            Scheduler.get().scheduleDeferred(newFolder);
355
        }
356
        else
357
            updateMetadata(folder.getUri() + "?update=", perms);
358
        }
359

    
360
        protected void updateMetadata(final String path, final Map<String, Boolean[]> newPermissions) {
361
        if (newPermissions != null) {
362
            PostRequest updateFolder = new PostRequest(app.getApiPath(), folder.getOwner(), path) {
363
                @Override
364
                public void onSuccess(@SuppressWarnings("unused") Resource result) {
365
                    app.updateFolder(folder.getParent(), false, null);
366
                }
367

    
368
                @Override
369
                public void onError(Throwable t) {
370
                    GWT.log("", t);
371
                    if (t instanceof RestException) {
372
                            if (((RestException) t).getHttpStatusCode() == Response.SC_NOT_FOUND) { //Probably a virtual folder
373
                            final String path1 = folder.getUri();
374
                            PutRequest newFolder = new PutRequest(app.getApiPath(), folder.getOwner(), path1) {
375
                                @Override
376
                                public void onSuccess(@SuppressWarnings("unused") Resource result) {
377
                                        updateMetadata(path, newPermissions);
378
                                }
379

    
380
                                @Override
381
                                public void onError(Throwable _t) {
382
                                    GWT.log("", _t);
383
                                    if(_t instanceof RestException){
384
                                        app.displayError("Unable to update folder: " + ((RestException) _t).getHttpStatusText());
385
                                    }
386
                                    else
387
                                        app.displayError("System error modifying folder: " + _t.getMessage());
388
                                }
389

    
390
                                                @Override
391
                                                protected void onUnauthorized(Response response) {
392
                                                        app.sessionExpired();
393
                                                }
394
                            };
395
                            newFolder.setHeader("X-Auth-Token", app.getToken());
396
                            newFolder.setHeader("Content-Type", "application/folder");
397
                            newFolder.setHeader("Accept", "*/*");
398
                            newFolder.setHeader("Content-Length", "0");
399
                            Scheduler.get().scheduleDeferred(newFolder);
400
                            }
401
                    }
402
                    else
403
                            app.displayError("System error modifying folder: " + t.getMessage());
404
                }
405

    
406
                                @Override
407
                                protected void onUnauthorized(Response response) {
408
                                        app.sessionExpired();
409
                                }
410
            };
411
            updateFolder.setHeader("X-Auth-Token", app.getToken());
412
            String readPermHeader = "read=";
413
            String writePermHeader = "write=";
414
            for (String u : newPermissions.keySet()) {
415
                Boolean[] p = newPermissions.get(u);
416
                if (p[0] != null && p[0])
417
                    readPermHeader += u + ",";
418
                if (p[1] != null && p[1])
419
                    writePermHeader += u + ",";
420
            }
421
            if (readPermHeader.endsWith("="))
422
                readPermHeader = "";
423
            else if (readPermHeader.endsWith(","))
424
                readPermHeader = readPermHeader.substring(0, readPermHeader.length() - 1);
425
            if (writePermHeader.endsWith("="))
426
                writePermHeader = "";
427
            else if (writePermHeader.endsWith(","))
428
                writePermHeader = writePermHeader.substring(0, writePermHeader.length() - 1);
429
            String permHeader = readPermHeader +  ((readPermHeader.length()  > 0 && writePermHeader.length() > 0) ?  ";" : "") + writePermHeader;
430
            if (permHeader.length() == 0)
431
                permHeader="~";
432
            updateFolder.setHeader("X-Object-Sharing", permHeader);
433
            Scheduler.get().scheduleDeferred(updateFolder);
434
        }
435
        else
436
            app.updateFolder(folder.getParent(), false, null);
437
    }
438

    
439
        public void selectTab(int _tab) {
440
                inner.selectTab(_tab);
441
        }
442
}