e2f1def855972caf0f4dcfff729977d20c432346
[pithos-web-client] / src / gr / grnet / pithos / web / client / FolderPropertiesDialog.java
1 /*\r
2  * Copyright 2011-2012 GRNET S.A. All rights reserved.\r
3  *\r
4  * Redistribution and use in source and binary forms, with or\r
5  * without modification, are permitted provided that the following\r
6  * conditions are met:\r
7  *\r
8  *   1. Redistributions of source code must retain the above\r
9  *      copyright notice, this list of conditions and the following\r
10  *      disclaimer.\r
11  *\r
12  *   2. Redistributions in binary form must reproduce the above\r
13  *      copyright notice, this list of conditions and the following\r
14  *      disclaimer in the documentation and/or other materials\r
15  *      provided with the distribution.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS\r
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR\r
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
28  * POSSIBILITY OF SUCH DAMAGE.\r
29  *\r
30  * The views and conclusions contained in the software and\r
31  * documentation are those of the authors and should not be\r
32  * interpreted as representing official policies, either expressed\r
33  * or implied, of GRNET S.A.\r
34  */\r
35 package gr.grnet.pithos.web.client;\r
36 \r
37 import com.google.gwt.core.client.GWT;\r
38 import com.google.gwt.core.client.Scheduler;\r
39 import com.google.gwt.dom.client.NativeEvent;\r
40 import com.google.gwt.event.dom.client.*;\r
41 import com.google.gwt.http.client.Response;\r
42 import com.google.gwt.i18n.client.DateTimeFormat;\r
43 import com.google.gwt.user.client.Command;\r
44 import com.google.gwt.user.client.Event.NativePreviewEvent;\r
45 import com.google.gwt.user.client.ui.*;\r
46 import gr.grnet.pithos.web.client.foldertree.Folder;\r
47 import gr.grnet.pithos.web.client.rest.PutRequest;\r
48 import gr.grnet.pithos.web.client.rest.RestException;\r
49 \r
50 /**\r
51  * The 'Folder properties' dialog box implementation.\r
52  */\r
53 public class FolderPropertiesDialog extends DialogBox {\r
54 \r
55     protected Pithos app;\r
56 \r
57     /**\r
58      * The widget that holds the folderName of the folder.\r
59      */\r
60     TextBox folderName = new TextBox();\r
61 \r
62     /**\r
63      * A flag that denotes whether the dialog will be used to create or modify a\r
64      * folder.\r
65      */\r
66     private final boolean create;\r
67 \r
68     final Folder folder;\r
69 \r
70     final VerticalPanel inner;\r
71 \r
72     /**\r
73      * The widget's constructor.\r
74      */\r
75     public FolderPropertiesDialog(final Pithos app, boolean _create, Folder selected) {\r
76         this.app = app;\r
77         Anchor close = new Anchor("close");\r
78         close.addStyleName("close");\r
79         close.addClickHandler(new ClickHandler() {\r
80 \r
81             @Override\r
82             public void onClick(ClickEvent event) {\r
83                 hide();\r
84             }\r
85         });\r
86 \r
87         setGlassEnabled(true);\r
88         setStyleName("pithos-DialogBox");\r
89 \r
90         // Enable IE selection for the dialog (must disable it upon closing it)\r
91         Pithos.enableIESelection();\r
92 \r
93         create = _create;\r
94 \r
95         folder = selected;\r
96 \r
97         // Use this opportunity to set the dialog's caption.\r
98         if(create) {\r
99             setText("Create folder");\r
100         }\r
101         else {\r
102             setText("Folder properties");\r
103         }\r
104 \r
105         // Outer contains inner and buttons\r
106         VerticalPanel outer = new VerticalPanel();\r
107         outer.add(close);\r
108         // Inner contains generalPanel and permPanel\r
109         inner = new VerticalPanel();\r
110         inner.addStyleName("inner");\r
111 \r
112         VerticalPanel generalPanel = new VerticalPanel();\r
113         FlexTable generalTable = new FlexTable();\r
114         generalTable.setText(0, 0, "Name");\r
115         generalTable.setText(1, 0, "Parent");\r
116         generalTable.setText(2, 0, "Creator");\r
117         generalTable.setText(3, 0, "Last modified");\r
118 \r
119         folderName.setText(create ? "" : folder.getName());\r
120         folderName.setReadOnly(folder.isContainer() && !create);\r
121         generalTable.setWidget(0, 1, folderName);\r
122 \r
123         final Label folderNameNote = new Label("Please note that slashes ('/') are not allowed in folder names.", true);\r
124         folderNameNote.setVisible(false);\r
125         folderNameNote.setStylePrimaryName("gss-readForAllNote");\r
126         generalTable.setWidget(0, 2, folderNameNote);\r
127 \r
128         if(create) {\r
129             generalTable.setText(1, 1, folder.getName());\r
130         }\r
131         else {\r
132             generalTable.setText(1, 1, folder.getParent().getName());\r
133         }\r
134         if(create) {\r
135             generalTable.setText(2, 1, app.getCurrentUserDisplayNameOrID());\r
136         }\r
137         else {\r
138             final String ownerID = folder.getOwnerID();\r
139             final String displayName = app.getUserDisplayNameForID(ownerID);\r
140             final String ownerDisplayName;\r
141             if(displayName == null) {\r
142                 // FIXME: Get the actual display name and do not use the id\r
143                 ownerDisplayName = ownerID;\r
144             }\r
145             else {\r
146                 ownerDisplayName = displayName;\r
147             }\r
148             generalTable.setText(2, 1, ownerDisplayName);\r
149         }\r
150         DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");\r
151         if(folder.getLastModified() != null) {\r
152             generalTable.setText(3, 1, formatter.format(folder.getLastModified()));\r
153         }\r
154         generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");\r
155         generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");\r
156         generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");\r
157         generalTable.getFlexCellFormatter().setStyleName(3, 0, "props-labels");\r
158         generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");\r
159         generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");\r
160         generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");\r
161         generalTable.getFlexCellFormatter().setStyleName(3, 1, "props-values");\r
162         generalTable.setCellSpacing(4);\r
163         generalPanel.add(generalTable);\r
164         inner.add(generalPanel);\r
165 \r
166         outer.add(inner);\r
167 \r
168         // Create the 'Create/Update' button, along with a listener that hides the dialog\r
169         // when the button is clicked and quits the application.\r
170         String okLabel;\r
171         if(create) {\r
172             okLabel = "Create";\r
173         }\r
174         else {\r
175             okLabel = "Update";\r
176         }\r
177         final Button ok = new Button(okLabel, new ClickHandler() {\r
178             @Override\r
179             public void onClick(ClickEvent event) {\r
180                 createOrUpdateFolder();\r
181                 closeDialog();\r
182             }\r
183         });\r
184         ok.addStyleName("button");\r
185         outer.add(ok);\r
186         outer.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);\r
187 \r
188         folderName.addChangeHandler(new ChangeHandler() {\r
189 \r
190             @Override\r
191             public void onChange(ChangeEvent event) {\r
192                 if(folderName.getText().contains("/")) {\r
193                     folderNameNote.setVisible(true);\r
194                     ok.setEnabled(false);\r
195                 }\r
196                 else {\r
197                     folderNameNote.setVisible(false);\r
198                     ok.setEnabled(true);\r
199                 }\r
200             }\r
201         });\r
202 \r
203         setWidget(outer);\r
204     }\r
205 \r
206     @Override\r
207     public void center() {\r
208         super.center();\r
209         folderName.setFocus(true);\r
210     }\r
211 \r
212     @Override\r
213     protected void onPreviewNativeEvent(NativePreviewEvent preview) {\r
214         super.onPreviewNativeEvent(preview);\r
215 \r
216         NativeEvent evt = preview.getNativeEvent();\r
217         if(evt.getType().equals(KeyDownEvent.getType().getName()))\r
218         // Use the popup's key preview hooks to close the dialog when either\r
219         // enter or escape is pressed.\r
220         {\r
221             switch(evt.getKeyCode()) {\r
222                 case KeyCodes.KEY_ENTER:\r
223                     createOrUpdateFolder();\r
224                     closeDialog();\r
225                     break;\r
226                 case KeyCodes.KEY_ESCAPE:\r
227                     closeDialog();\r
228                     break;\r
229             }\r
230         }\r
231     }\r
232 \r
233 \r
234     /**\r
235      * Enables IE selection prevention and hides the dialog\r
236      * (we disable the prevention on creation of the dialog)\r
237      */\r
238     public void closeDialog() {\r
239         Pithos.preventIESelection();\r
240         hide();\r
241     }\r
242 \r
243     /**\r
244      * Generate an RPC request to create a new folder.\r
245      */\r
246     private void createFolder() {\r
247         String name = folderName.getText().trim();\r
248         if(name.length() == 0) {\r
249             return;\r
250         }\r
251         String path = folder.getUri() + "/" + name;\r
252         PutRequest createFolder = new PutRequest(app.getApiPath(), folder.getOwnerID(), path) {\r
253             @Override\r
254             public void onSuccess(Resource result) {\r
255                 app.updateFolder(folder, true, new Command() {\r
256 \r
257                     @Override\r
258                     public void execute() {\r
259                         app.updateStatistics();\r
260                     }\r
261                 }, true);\r
262             }\r
263 \r
264             @Override\r
265             public void onError(Throwable t) {\r
266                 GWT.log("", t);\r
267                 app.setError(t);\r
268                 if(t instanceof RestException) {\r
269                     app.displayError("Unable to create folder:" + ((RestException) t).getHttpStatusText());\r
270                 }\r
271                 else {\r
272                     app.displayError("System error creating folder:" + t.getMessage());\r
273                 }\r
274             }\r
275 \r
276             @Override\r
277             protected void onUnauthorized(Response response) {\r
278                 app.sessionExpired();\r
279             }\r
280         };\r
281         createFolder.setHeader("X-Auth-Token", app.getUserToken());\r
282         createFolder.setHeader("Accept", "*/*");\r
283         createFolder.setHeader("Content-Length", "0");\r
284         createFolder.setHeader("Content-Type", "application/directory");\r
285         Scheduler.get().scheduleDeferred(createFolder);\r
286     }\r
287 \r
288     /**\r
289      * Upon closing the dialog by clicking OK or pressing ENTER this method does\r
290      * the actual work of modifying folder properties or creating a new Folder\r
291      * depending on the value of the create field\r
292      */\r
293     protected void createOrUpdateFolder() {\r
294         if(create) {\r
295             createFolder();\r
296         }\r
297         else {\r
298             updateFolder();\r
299         }\r
300 \r
301     }\r
302 \r
303     private void updateFolder() {\r
304         final String newName = folderName.getText().trim();\r
305         if(newName.length() == 0) {\r
306             return;\r
307         }\r
308         if(!folder.isContainer() && !folder.getName().equals(newName)) {\r
309             final String path = folder.getParent().getUri() + "/" + newName;\r
310             app.copyFolder(folder, folder.getOwnerID(), path, true, new Command() {\r
311 \r
312                 @Override\r
313                 public void execute() {\r
314                     app.updateFolder(folder.getParent(), false, new Command() {\r
315 \r
316                         @Override\r
317                         public void execute() {\r
318                             app.updateMySharedRoot();\r
319                         }\r
320                     }, true);\r
321                 }\r
322             });\r
323         }\r
324         else {\r
325             app.updateFolder(folder.getParent(), false, new Command() {\r
326 \r
327                 @Override\r
328                 public void execute() {\r
329                     app.updateMySharedRoot();\r
330                 }\r
331             }, true);\r
332         }\r
333     }\r
334 }\r