CSS and aesthetic changes
[pithos-web-client] / src / gr / grnet / pithos / web / client / FilePropertiesDialog.java
1 /*\r
2  * Copyright 2011 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 gr.grnet.pithos.web.client.foldertree.File;\r
38 import gr.grnet.pithos.web.client.foldertree.FileVersions;\r
39 import gr.grnet.pithos.web.client.foldertree.Resource;\r
40 import gr.grnet.pithos.web.client.foldertree.Version;\r
41 import gr.grnet.pithos.web.client.rest.GetRequest;\r
42 import gr.grnet.pithos.web.client.rest.PostRequest;\r
43 import gr.grnet.pithos.web.client.rest.PutRequest;\r
44 import gr.grnet.pithos.web.client.rest.RestException;\r
45 import gr.grnet.pithos.web.client.tagtree.Tag;\r
46 \r
47 import java.util.List;\r
48 import java.util.Map;\r
49 \r
50 import com.google.gwt.core.client.GWT;\r
51 import com.google.gwt.core.client.Scheduler;\r
52 import com.google.gwt.event.dom.client.ClickEvent;\r
53 import com.google.gwt.event.dom.client.ClickHandler;\r
54 import com.google.gwt.http.client.Response;\r
55 import com.google.gwt.i18n.client.DateTimeFormat;\r
56 import com.google.gwt.resources.client.ImageResource;\r
57 import com.google.gwt.user.client.Window;\r
58 import com.google.gwt.user.client.ui.Anchor;\r
59 import com.google.gwt.user.client.ui.Button;\r
60 import com.google.gwt.user.client.ui.CheckBox;\r
61 import com.google.gwt.user.client.ui.DecoratedTabPanel;\r
62 import com.google.gwt.user.client.ui.DisclosurePanel;\r
63 import com.google.gwt.user.client.ui.FlexTable;\r
64 import com.google.gwt.user.client.ui.FlowPanel;\r
65 import com.google.gwt.user.client.ui.FocusPanel;\r
66 import com.google.gwt.user.client.ui.HasHorizontalAlignment;\r
67 import com.google.gwt.user.client.ui.HorizontalPanel;\r
68 import com.google.gwt.user.client.ui.Label;\r
69 import com.google.gwt.user.client.ui.TextBox;\r
70 import com.google.gwt.user.client.ui.VerticalPanel;\r
71 \r
72 /**\r
73  * The 'File properties' dialog box implementation.\r
74  *\r
75  */\r
76 public class FilePropertiesDialog extends AbstractPropertiesDialog {\r
77 \r
78         protected PermissionsList permList;\r
79 \r
80         protected CheckBox readForAll;\r
81 \r
82         /**\r
83          * An image bundle for this widgets images.\r
84          */\r
85         public interface Images extends MessagePanel.Images {\r
86 \r
87                 @Source("gr/grnet/pithos/resources/edit_user.png")\r
88                 ImageResource permUser();\r
89 \r
90                 @Source("gr/grnet/pithos/resources/groups22.png")\r
91                 ImageResource permGroup();\r
92 \r
93                 @Source("gr/grnet/pithos/resources/editdelete.png")\r
94                 ImageResource delete();\r
95 \r
96                 @Source("gr/grnet/pithos/resources/db_update.png")\r
97                 ImageResource restore();\r
98 \r
99                 @Source("gr/grnet/pithos/resources/folder_inbox.png")\r
100                 ImageResource download();\r
101         }\r
102 \r
103         /**\r
104          * The widget that holds the name of the file.\r
105          */\r
106         private TextBox name = new TextBox();\r
107 \r
108         final File file;\r
109 \r
110     Images images = GWT.create(Images.class);\r
111 \r
112         /**\r
113          * The widget's constructor.\r
114          */\r
115         public FilePropertiesDialog(Pithos _app, File _file) {\r
116         super(_app);\r
117         file = _file;\r
118 \r
119                 // Set the dialog's caption.\r
120                 setText("File properties");\r
121 \r
122                 // Outer contains inner and buttons.\r
123                 final VerticalPanel outer = new VerticalPanel();\r
124                 final FocusPanel focusPanel = new FocusPanel(outer);\r
125                 // Inner contains generalPanel and permPanel.\r
126                 inner = new DecoratedTabPanel();\r
127                 inner.setAnimationEnabled(true);\r
128 \r
129 \r
130         inner.add(createGeneralPanel(), "General");\r
131 \r
132         inner.add(createSharingPanel(), "Sharing");\r
133 \r
134                 fetchVersions();\r
135                         \r
136         inner.selectTab(0);\r
137 \r
138         outer.add(inner);\r
139 \r
140                 final HorizontalPanel buttons = new HorizontalPanel();\r
141                 // Create the 'OK' button, along with a listener that hides the dialog\r
142                 // when the button is clicked.\r
143                 final Button ok = new Button("OK", new ClickHandler() {\r
144                         @Override\r
145                         public void onClick(@SuppressWarnings("unused") ClickEvent event) {\r
146                                 accept();\r
147                                 closeDialog();\r
148                         }\r
149                 });\r
150 \r
151                 buttons.add(ok);\r
152                 buttons.setCellHorizontalAlignment(ok, HasHorizontalAlignment.ALIGN_CENTER);\r
153                 // Create the 'Cancel' button, along with a listener that hides the\r
154                 // dialog when the button is clicked.\r
155                 final Button cancel = new Button("Cancel", new ClickHandler() {\r
156                         @Override\r
157                         public void onClick(@SuppressWarnings("unused") ClickEvent event) {\r
158                                 closeDialog();\r
159                         }\r
160                 });\r
161                 buttons.add(cancel);\r
162                 buttons.setCellHorizontalAlignment(cancel, HasHorizontalAlignment.ALIGN_CENTER);\r
163                 buttons.setSpacing(8);\r
164                 buttons.addStyleName("pithos-TabPanelBottom");\r
165 \r
166         outer.add(buttons);\r
167         outer.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);\r
168         outer.addStyleName("pithos-TabPanelBottom");\r
169 \r
170         focusPanel.setFocus(true);\r
171         setWidget(outer);\r
172         }\r
173 \r
174     protected void fetchVersions() {\r
175         String path = file.getUri() + "?format=json&version=list";\r
176         GetRequest<FileVersions> getVersions = new GetRequest<FileVersions>(FileVersions.class, app.getApiPath(), file.getOwner(), path) {\r
177 \r
178                         @Override\r
179                         public void onSuccess(FileVersions _result) {\r
180                         inner.add(createVersionPanel(_result.getVersions()), "Versions");\r
181                         }\r
182 \r
183                         @Override\r
184                         public void onError(Throwable t) {\r
185                 if (t instanceof RestException) {\r
186                     app.displayError("Unable to fetch versions: " + ((RestException) t).getHttpStatusText());\r
187                 }\r
188                 else\r
189                     app.displayError("System error unable to fetch versions: "+t.getMessage());\r
190                         }\r
191 \r
192                         @Override\r
193                         protected void onUnauthorized(Response response) {\r
194                                 app.sessionExpired();\r
195                         }\r
196                 };\r
197                 getVersions.setHeader("X-Auth-Token", app.getToken());\r
198                 Scheduler.get().scheduleDeferred(getVersions);\r
199         }\r
200 \r
201         private VerticalPanel createGeneralPanel() {\r
202         final VerticalPanel generalPanel = new VerticalPanel();\r
203         final FlexTable generalTable = new FlexTable();\r
204         generalTable.setText(0, 0, "Name");\r
205         generalTable.setText(1, 0, "Folder");\r
206         generalTable.setText(2, 0, "Owner");\r
207         generalTable.setText(3, 0, "Last modified");\r
208         generalTable.setText(4, 0, "Tags");\r
209 \r
210         name.setWidth("100%");\r
211         name.setText(file.getName());\r
212         generalTable.setWidget(0, 1, name);\r
213         if(file.getParent() != null)\r
214             generalTable.setText(1, 1, file.getParent().getName());\r
215         else\r
216             generalTable.setText(1, 1, "-");\r
217         generalTable.setText(2, 1, file.getOwner());\r
218 \r
219         final DateTimeFormat formatter = DateTimeFormat.getFormat("d/M/yyyy h:mm a");\r
220         generalTable.setText(3, 1, formatter.format(file.getLastModified()));\r
221 \r
222                 StringBuffer tagsBuffer = new StringBuffer();\r
223         for (String t : file.getTags())\r
224                         tagsBuffer.append(t).append(", ");\r
225                 if (tagsBuffer.length() > 1)\r
226                         tagsBuffer.delete(tagsBuffer.length() - 2, tagsBuffer.length() - 1);\r
227                 initialTagText = tagsBuffer.toString();\r
228                 tags.setWidth("100%");\r
229                 tags.setText(initialTagText);\r
230                 generalTable.setWidget(4, 1, tags);\r
231 \r
232         generalTable.getFlexCellFormatter().setStyleName(0, 0, "props-labels");\r
233         generalTable.getFlexCellFormatter().setStyleName(1, 0, "props-labels");\r
234         generalTable.getFlexCellFormatter().setStyleName(2, 0, "props-labels");\r
235         generalTable.getFlexCellFormatter().setStyleName(3, 0, "props-labels");\r
236         generalTable.getFlexCellFormatter().setStyleName(4, 0, "props-labels");\r
237         generalTable.getFlexCellFormatter().setStyleName(0, 1, "props-values");\r
238         generalTable.getFlexCellFormatter().setStyleName(1, 1, "props-values");\r
239         generalTable.getFlexCellFormatter().setStyleName(2, 1, "props-values");\r
240         generalTable.getFlexCellFormatter().setStyleName(3, 1, "props-values");\r
241         generalTable.getFlexCellFormatter().setStyleName(4, 1, "props-values");\r
242         generalTable.setCellSpacing(4);\r
243 \r
244         generalPanel.add(generalTable);\r
245 \r
246         DisclosurePanel allTags = new DisclosurePanel("All tags");\r
247         allTagsContent = new FlowPanel();\r
248         allTagsContent.setWidth("100%");\r
249         for (Tag t : app.getAllTags()) {\r
250             final Anchor tagAnchor = new Anchor(t.getName(), false);\r
251             tagAnchor.addStyleName("pithos-tag");\r
252             allTagsContent.add(tagAnchor);\r
253             Label separator = new Label(", ");\r
254             separator.addStyleName("pithos-tag");\r
255             allTagsContent.add(separator);\r
256             tagAnchor.addClickHandler(new ClickHandler() {\r
257 \r
258                 @Override\r
259                 public void onClick(@SuppressWarnings("unused") ClickEvent event) {\r
260                     String existing = tags.getText().trim();\r
261                     if (MULTIPLE_VALUES_TEXT.equals(existing))\r
262                         existing = "";\r
263                     String newTag = tagAnchor.getText().trim();\r
264                     // insert the new tag only if it is not in the list\r
265                     // already\r
266                     if (existing.indexOf(newTag) == -1)\r
267                         tags.setText(existing + (existing.length() > 0 ? ", " : "") + newTag);\r
268                 }\r
269             });\r
270         }\r
271         allTags.setContent(allTagsContent);\r
272         generalPanel.add(allTags);\r
273         generalPanel.setSpacing(4);\r
274         return generalPanel;\r
275     }\r
276 \r
277     private VerticalPanel createSharingPanel() {\r
278         VerticalPanel permPanel = new VerticalPanel();\r
279 \r
280         permList = new PermissionsList(images, file.getPermissions(), file.getOwner(), file.getInheritedPermissionsFrom() != null);\r
281         permPanel.add(permList);\r
282 \r
283         if (file.getInheritedPermissionsFrom() == null) {\r
284             HorizontalPanel permButtons = new HorizontalPanel();\r
285             Button add = new Button("Add Group", new ClickHandler() {\r
286                 @Override\r
287                 public void onClick(@SuppressWarnings("unused") ClickEvent event) {\r
288                     PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, false);\r
289                     dlg.center();\r
290                     permList.updatePermissionTable();\r
291                 }\r
292             });\r
293             permButtons.add(add);\r
294             permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);\r
295 \r
296             final Button addUser = new Button("Add User", new ClickHandler() {\r
297                 @Override\r
298                 public void onClick(@SuppressWarnings("unused") ClickEvent event) {\r
299                     PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, true);\r
300                     dlg.center();\r
301                     permList.updatePermissionTable();\r
302                 }\r
303             });\r
304             permButtons.add(addUser);\r
305             permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);\r
306 \r
307             permButtons.setSpacing(8);\r
308             permButtons.addStyleName("pithos-TabPanelBottom");\r
309             permPanel.add(permButtons);\r
310         }\r
311 \r
312         final Label readForAllNote = new Label("When this option is enabled, the file will be readable" +\r
313                     " by everyone. By checking this option, you are certifying that you have the right to " +\r
314                     "distribute this file and that it does not violate the Terms of Use.", true);\r
315         readForAllNote.setVisible(false);\r
316         readForAllNote.setStylePrimaryName("pithos-readForAllNote");\r
317 \r
318         readForAll = new CheckBox();\r
319         readForAll.setValue(file.isPublished());\r
320         readForAll.addClickHandler(new ClickHandler() {\r
321             @Override\r
322             public void onClick(@SuppressWarnings("unused") ClickEvent event) {\r
323                 readForAllNote.setVisible(readForAll.getValue());\r
324             }\r
325         });\r
326 \r
327         // Only show the read for all permission if the user is the owner.\r
328         if (file.getOwner().equals(app.getUsername())) {\r
329             final HorizontalPanel permForAll = new HorizontalPanel();\r
330             permForAll.add(new Label("Public"));\r
331             permForAll.add(readForAll);\r
332             permForAll.setSpacing(8);\r
333             permForAll.addStyleName("pithos-TabPanelBottom");\r
334             permForAll.add(readForAllNote);\r
335             permPanel.add(permForAll);\r
336         }\r
337 \r
338         if (file.isPublished()) {\r
339             final HorizontalPanel pathPanel = new HorizontalPanel();\r
340             pathPanel.setWidth("100%");\r
341             pathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);\r
342             pathPanel.add(new Label("Link"));\r
343             pathPanel.setSpacing(8);\r
344             pathPanel.addStyleName("pithos-TabPanelBottom");\r
345 \r
346             TextBox path = new TextBox();\r
347             path.setWidth("100%");\r
348             path.addClickHandler(new ClickHandler() {\r
349                 @Override\r
350                 public void onClick(ClickEvent event) {\r
351                     Pithos.enableIESelection();\r
352                     ((TextBox) event.getSource()).selectAll();\r
353                     Pithos.preventIESelection();\r
354                 }\r
355             });\r
356             path.setText(Window.Location.getHost() + file.getPublicUri());\r
357             path.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");\r
358             path.setWidth("100%");\r
359             path.setReadOnly(true);\r
360             pathPanel.add(path);\r
361             permPanel.add(pathPanel);\r
362         }\r
363 \r
364         return permPanel;\r
365     }\r
366 \r
367     VerticalPanel createVersionPanel(List<Version> versions) {\r
368         VerticalPanel versionPanel = new VerticalPanel();\r
369         VersionsList verList = new VersionsList(app, this, images, file, versions);\r
370         versionPanel.add(verList);\r
371         return versionPanel;\r
372     }\r
373 \r
374         /**\r
375          * Accepts any change and updates the file\r
376          *\r
377          */\r
378         @Override\r
379         protected void accept() {\r
380                 String newFilename = null;\r
381 \r
382                 final Map<String, Boolean[]> perms = (permList.hasChanges() ? permList.getPermissions() : null);\r
383 \r
384                 if (!name.getText().trim().equals(file.getName())) {\r
385                         newFilename = name.getText().trim();\r
386                 }\r
387 \r
388                 //only update the read for all perm if the user is the owner\r
389         Boolean published = null;\r
390                 if (readForAll.getValue() != file.isPublished())\r
391                         if (file.getOwner().equals(app.getUsername()))\r
392                 published = readForAll.getValue();\r
393         final Boolean finalPublished = published;\r
394 \r
395         String[] tagset = null;\r
396                 if (!tags.getText().equals(initialTagText))\r
397                         tagset = tags.getText().trim().split(",");\r
398         final String[] newTags = tagset;\r
399 \r
400         if (newFilename != null) {\r
401             final String path = file.getParent().getUri() + "/" + newFilename;\r
402             PutRequest updateFile = new PutRequest(app.getApiPath(), app.getUsername(), path) {\r
403                 @Override\r
404                 public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
405                     updateMetaData(app.getApiPath(), file.getOwner(), path + "?update=", newTags, finalPublished, perms);\r
406                 }\r
407 \r
408                 @Override\r
409                 public void onError(Throwable t) {\r
410                     GWT.log("", t);\r
411                     app.displayError("System error modifying file:" + t.getMessage());\r
412                 }\r
413 \r
414                                 @Override\r
415                                 protected void onUnauthorized(Response response) {\r
416                                         app.sessionExpired();\r
417                                 }\r
418             };\r
419             updateFile.setHeader("X-Auth-Token", app.getToken());\r
420             updateFile.setHeader("X-Move-From", file.getUri());\r
421             updateFile.setHeader("Content-Type", file.getContentType());\r
422             Scheduler.get().scheduleDeferred(updateFile);\r
423         }\r
424         else\r
425             updateMetaData(app.getApiPath(), app.getUsername(), file.getUri() + "?update=", newTags, finalPublished, perms);\r
426         }\r
427 \r
428         protected void updateMetaData(String api, String owner, String path, String[] newTags, Boolean published, Map<String, Boolean[]> newPermissions) {\r
429         if (newTags != null || published != null || newPermissions != null) {\r
430             PostRequest updateFile = new PostRequest(api, owner, path) {\r
431                 @Override\r
432                 public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
433                     app.updateFolder(file.getParent(), true, null);\r
434                 }\r
435 \r
436                 @Override\r
437                 public void onError(Throwable t) {\r
438                     GWT.log("", t);\r
439                     app.displayError("System error modifying file:" + t.getMessage());\r
440                 }\r
441 \r
442                                 @Override\r
443                                 protected void onUnauthorized(Response response) {\r
444                                         app.sessionExpired();\r
445                                 }\r
446             };\r
447             updateFile.setHeader("X-Auth-Token", app.getToken());\r
448             if (newTags != null)\r
449                 for (String t : newTags)\r
450                         if (t.length() > 0)\r
451                                 updateFile.setHeader("X-Object-Meta-" + t.trim(), "true");\r
452                 for (String t : file.getTags())\r
453                         updateFile.setHeader("X-Object-Meta-" + t.trim(), "~");\r
454             if (published != null)\r
455                 updateFile.setHeader("X-Object-Public", published.toString());\r
456             if (newPermissions != null) {\r
457                 String readPermHeader = "read=";\r
458                 String writePermHeader = "write=";\r
459                 for (String u : newPermissions.keySet()) {\r
460                     Boolean[] p = newPermissions.get(u);\r
461                     if (p[0] != null && p[0])\r
462                         readPermHeader += u + ",";\r
463                     if (p[1] != null && p[1])\r
464                         writePermHeader += u + ",";\r
465                 }\r
466                 if (readPermHeader.endsWith("="))\r
467                     readPermHeader = "";\r
468                 else if (readPermHeader.endsWith(","))\r
469                     readPermHeader = readPermHeader.substring(0, readPermHeader.length() - 1);\r
470                 if (writePermHeader.endsWith("="))\r
471                     writePermHeader = "";\r
472                 else if (writePermHeader.endsWith(","))\r
473                     writePermHeader = writePermHeader.substring(0, writePermHeader.length() - 1);\r
474                 String permHeader = readPermHeader +  ((readPermHeader.length()  > 0 && writePermHeader.length() > 0) ?  ";" : "") + writePermHeader;\r
475                 if (permHeader.length() == 0)\r
476                     permHeader="~";\r
477                 updateFile.setHeader("X-Object-Sharing", permHeader);\r
478             }\r
479             Scheduler.get().scheduleDeferred(updateFile);\r
480         }\r
481         else\r
482             app.updateFolder(file.getParent(), true, null);\r
483     }\r
484 }\r