2 * Copyright 2011-2013 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
35 package gr.grnet.pithos.web.client;
37 import com.google.gwt.http.client.URL;
38 import com.google.gwt.user.client.ui.*;
39 import gr.grnet.pithos.web.client.foldertree.File;
40 import gr.grnet.pithos.web.client.rest.HeadRequest;
41 import gr.grnet.pithos.web.client.rest.PostRequest;
43 import com.google.gwt.core.client.GWT;
44 import com.google.gwt.core.client.Scheduler;
45 import com.google.gwt.dom.client.NativeEvent;
46 import com.google.gwt.event.dom.client.ClickEvent;
47 import com.google.gwt.event.dom.client.ClickHandler;
48 import com.google.gwt.event.dom.client.KeyCodes;
49 import com.google.gwt.http.client.Response;
50 import com.google.gwt.http.client.UrlBuilder;
51 import com.google.gwt.resources.client.ImageResource;
52 import com.google.gwt.user.client.Command;
53 import com.google.gwt.user.client.Window;
54 import com.google.gwt.user.client.Event.NativePreviewEvent;
59 * UI for the "Share" command.
61 public class FileShareDialog extends AbstractPropertiesDialog {
63 private final HorizontalPanel publicPathPanel = new HorizontalPanel();
64 private final TextBox publicPathText = new TextBox();
66 // For private sharing
67 private final HorizontalPanel privatePathPanel = new HorizontalPanel();
68 private final TextBox privatePathText = new TextBox();
69 private final VerticalPanel privatePermSuperPanel = new VerticalPanel();
70 private PermissionsList permList;
73 * An image bundle for this widgets images.
75 public interface PublicSharingImages extends MessagePanel.Images {
77 @Source("gr/grnet/pithos/resources/edit_user.png")
78 ImageResource permUser();
80 @Source("gr/grnet/pithos/resources/groups22.png")
81 ImageResource permGroup();
83 @Source("gr/grnet/pithos/resources/editdelete.png")
84 ImageResource delete();
87 public interface PrivateSharingImages extends MessagePanel.Images {
89 @Source("gr/grnet/pithos/resources/edit_user.png")
90 ImageResource permUser();
92 @Source("gr/grnet/pithos/resources/groups22.png")
93 ImageResource permGroup();
95 @Source("gr/grnet/pithos/resources/delete.gif")
96 ImageResource delete();
99 private final File file;
101 private final PublicSharingImages publicSharingImages = GWT.create(PublicSharingImages.class);
102 private final PrivateSharingImages privateSharingImages = GWT.create(PrivateSharingImages.class);
105 * The widget's constructor.
107 public FileShareDialog(Pithos app, File file) {
111 Anchor close = new Anchor("close");
112 close.addStyleName("close");
113 close.addClickHandler(new ClickHandler() {
116 public void onClick(ClickEvent event) {
120 // Set the dialog's caption.
122 setGlassEnabled(true);
123 setStyleName("pithos-DialogBox");
125 // Outer contains inner and buttons.
126 final VerticalPanel outer = new VerticalPanel();
128 final FocusPanel focusPanel = new FocusPanel(outer);
129 // Inner contains generalPanel and permPanel.
130 inner = new VerticalPanel();
131 inner.addStyleName("inner");
133 inner.add(createMainPanel());
137 final Button ok = new Button("OK", new ClickHandler() {
139 public void onClick(ClickEvent event) {
143 ok.addStyleName("button");
146 outer.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);
148 focusPanel.setFocus(true);
152 private boolean IamOwner() {
153 return file.getOwnerID().equals(app.getUserID());
156 private void populatePublicSharingPanel(VerticalPanel publicSharingPanel) {
158 final HorizontalPanel publicCheckPanel = new HorizontalPanel();
159 publicCheckPanel.setSpacing(8);
162 final CheckBox publicCheckBox = new CheckBox();
163 Label publicCheckTitle = new InlineHTML("<b>Public on the Internet</b>");
164 Label publicCheckInfo = new Label("Anyone who has the public link can access. No sign-in required.", true);
166 publicCheckBox.setValue(isFilePubliclyShared());
167 publicCheckBox.addClickHandler(new ClickHandler() {
169 public void onClick(ClickEvent event) {
170 final Boolean published;
171 if(publicCheckBox.getValue() != file.isPublished() && IamOwner()) {
172 published = publicCheckBox.getValue();
175 published = Boolean.FALSE;
178 updateMetaDataForPublicSharing(published);
182 publicCheckPanel.add(publicCheckBox);
183 publicCheckPanel.add(publicCheckTitle);
184 publicCheckPanel.add(publicCheckInfo);
187 publicPathPanel.setVisible(false);
188 publicPathPanel.setWidth(Const.PERCENT_100);
189 publicPathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
190 publicPathPanel.add(new Label("Link"));
191 publicPathPanel.setSpacing(8);
192 publicPathPanel.addStyleName("pithos-TabPanelBottom");
194 publicPathText.setWidth(Const.PERCENT_100);
195 publicPathText.addClickHandler(new ClickHandler() {
197 public void onClick(ClickEvent event) {
198 Pithos.enableIESelection();
199 ((TextBox) event.getSource()).selectAll();
200 Pithos.preventIESelection();
203 publicPathText.setText(Window.Location.getHost() + file.getPublicUri());
204 publicPathText.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");
205 publicPathText.setReadOnly(true);
206 publicPathPanel.add(publicPathText);
208 publicSharingPanel.add(publicCheckPanel);
209 publicSharingPanel.add(publicPathPanel);
211 Scheduler.get().scheduleDeferred(new Command() {
213 public void execute() {
214 showLinkForPublicSharing();
220 private void populatePrivateSharingPanel(VerticalPanel privateSharingPanel) {
221 final HorizontalPanel privateCheckPanel = new HorizontalPanel();
222 final VerticalPanel privatePermPanel = new VerticalPanel();
223 final HorizontalPanel permButtons = new HorizontalPanel();
225 privateCheckPanel.setSpacing(8);
226 privatePermPanel.setVisible(isFilePrivatelyShared());
227 permButtons.setSpacing(8);
230 final CheckBox privateCheckBox = new CheckBox();
231 final Label privateCheckTitle = new InlineHTML("<b>Private sharing</b>");
232 final Label privateCheckInfo = new Label("Only people explicitly granted permission can access. Sign-in required.", true);
234 privateCheckBox.setValue(isFilePrivatelyShared());
235 privateCheckBox.addClickHandler(new ClickHandler() {
237 public void onClick(ClickEvent event) {
238 if(isFilePrivatelyShared()) {
239 // ignore the click, set it always to "checked"
240 privateCheckBox.setValue(true);
242 privatePermPanel.setVisible(true);
245 // This is the value *after* the click is applied :)
246 boolean isChecked = privateCheckBox.getValue();
247 privatePermPanel.setVisible(isChecked);
252 privateCheckPanel.add(privateCheckBox);
253 privateCheckPanel.add(privateCheckTitle);
254 privateCheckPanel.add(privateCheckInfo);
257 permList = new PermissionsList(app, privateSharingImages, file.getPermissions(), file.getOwnerID(), false, new Command() {
259 public void execute() {
260 updateMetaDataForPrivateSharing();
264 // Permission Add buttons
265 Button addUser = new Button("Add User", new ClickHandler() {
267 public void onClick(ClickEvent event) {
268 PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, true);
270 permList.updatePermissionTable();
273 addUser.addStyleName("button");
274 permButtons.add(addUser);
276 final boolean haveGroups = app.getAccount().getGroups().size() > 0;
277 Button addGroup = new Button("Add Group", new ClickHandler() {
279 public void onClick(ClickEvent event) {
280 PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, false);
282 permList.updatePermissionTable();
285 addGroup.addStyleName("button");
286 addGroup.setEnabled(haveGroups);
288 addGroup.setTitle("You do not have any groups");
290 permButtons.add(addGroup);
292 Button addEverybody = new Button("Add everybody", new ClickHandler() {
294 public void onClick(ClickEvent event) {
295 Pithos.LOG("Adding to Everybody");
297 permList.addPermission("*", true, false);
298 permList.updatePermissionTable();
301 addEverybody.addStyleName("button");
302 permButtons.add(addEverybody);
304 permButtons.setCellHorizontalAlignment(addGroup, HasHorizontalAlignment.ALIGN_CENTER);
305 privatePermPanel.add(permList);
306 privatePermPanel.add(permButtons);
309 privatePathPanel.setVisible(false);
310 privatePathPanel.setWidth(Const.PERCENT_100);
311 privatePathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
312 privatePathPanel.add(new Label("Link"));
313 privatePathPanel.setSpacing(8);
314 privatePathPanel.addStyleName("pithos-TabPanelBottom");
316 privatePathText.setWidth(Const.PERCENT_100);
317 privatePathText.addClickHandler(new ClickHandler() {
319 public void onClick(ClickEvent event) {
320 Pithos.enableIESelection();
321 ((TextBox) event.getSource()).selectAll();
322 Pithos.preventIESelection();
325 privatePathText.setText(Window.Location.getHost() + file.getPublicUri());
326 privatePathText.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");
327 privatePathText.setWidth(Const.PERCENT_100);
328 privatePathText.setReadOnly(true);
329 privatePathPanel.add(privatePathText);
331 Scheduler.get().scheduleDeferred(new Command() {
333 public void execute() {
334 showLinkForPrivateSharing();
338 privateSharingPanel.add(privateCheckPanel);
339 privateSharingPanel.add(privatePermPanel);
340 privateSharingPanel.add(privatePathPanel);
343 private Panel createMainPanel() {
344 VerticalPanel panelAll = new VerticalPanel();
345 VerticalPanel panelPublic = new VerticalPanel();
346 VerticalPanel panelPrivate = new VerticalPanel();
348 populatePrivateSharingPanel(panelPrivate);
349 populatePublicSharingPanel(panelPublic);
351 CaptionPanel captionPanelPrivate = new CaptionPanel();
352 CaptionPanel captionPanelPublic = new CaptionPanel();
353 captionPanelPrivate.add(panelPrivate);
354 captionPanelPublic.add(panelPublic);
356 panelAll.add(captionPanelPrivate);
357 panelAll.add(captionPanelPublic);
362 private boolean isFilePubliclyShared() {
363 return file.isPublished();
366 private boolean isFilePrivatelyShared() {
367 return file.isShared();
370 private void showLinkForPublicSharing() {
371 if (isFilePubliclyShared()) {
372 UrlBuilder b = Window.Location.createUrlBuilder();
373 b.setPath(file.getPublicUri());
374 publicPathText.setText(b.buildString());
375 publicPathPanel.setVisible(true);
378 publicPathPanel.setVisible(false);
382 private void showLinkForPrivateSharing() {
383 if (isFilePrivatelyShared()) {
384 UrlBuilder b = Window.Location.createUrlBuilder();
385 b.setPath(app.getApiPath() + file.getOwnerID() + file.getUri());
386 String href = Window.Location.getHref();
387 boolean hasParameters = href.contains(Const.QUESTION_MARK);
388 privatePathText.setText(href + (hasParameters ? Const.AMPERSAND : Const.QUESTION_MARK) + Const.GOTO_EQ + b.buildString());
389 privatePathPanel.setVisible(true);
392 privatePathPanel.setVisible(false);
396 protected void updateMetaDataForPublicSharing(String api, String owner, final String path, final Boolean published) {
397 if (published != null) {
398 PostRequest updateFile = new PostRequest(api, owner, path) {
400 public void onSuccess(Resource result) {
401 HeadRequest<File> headFile = new HeadRequest<File>(File.class, app.getApiPath(), file.getOwnerID(), path, file) {
404 public void onSuccess(File _result) {
405 showLinkForPublicSharing();
406 if (!app.isMySharedSelected()) {
407 app.updateFolder(file.getParent(), true, new Command() {
410 public void execute() {
411 app.updateMySharedRoot();
416 app.updateSharedFolder(file.getParent(), true);
421 public void onError(Throwable t) {
423 app.displayError("System error modifying file:" + t.getMessage());
427 protected void onUnauthorized(Response response) {
428 app.sessionExpired();
431 headFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
432 Scheduler.get().scheduleDeferred(headFile);
436 public void onError(Throwable t) {
438 app.displayError("System error modifying file:" + t.getMessage());
442 protected void onUnauthorized(Response response) {
443 app.sessionExpired();
446 updateFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
447 updateFile.setHeader(Const.X_OBJECT_PUBLIC, published.toString());
448 Scheduler.get().scheduleDeferred(updateFile);
450 else if (!app.isMySharedSelected())
451 app.updateFolder(file.getParent(), true, new Command() {
453 public void execute() {
454 if (file.isSharedOrPublished()) {
455 app.updateMySharedRoot();
460 app.updateSharedFolder(file.getParent(), true);
462 protected void updateMetaDataForPublicSharing(Boolean published) {
463 updateMetaDataForPublicSharing(
466 file.getUri() + Const.QUESTION_MARK_UPDATE_EQ,
471 protected void updateMetaDataForPrivateSharing(String api, String owner, final String path, final Map<String, Boolean[]> newPermissions) {
472 if (newPermissions != null) {
473 PostRequest updateFile = new PostRequest(api, owner, path) {
475 public void onSuccess(Resource result) {
476 HeadRequest<File> headFile = new HeadRequest<File>(File.class, app.getApiPath(), file.getOwnerID(), path, file) {
479 public void onSuccess(File _result) {
480 showLinkForPrivateSharing();
481 if (!app.isMySharedSelected())
482 app.updateFolder(file.getParent(), true, new Command() {
485 public void execute() {
486 app.updateMySharedRoot();
490 app.updateSharedFolder(file.getParent(), true);
494 public void onError(Throwable t) {
496 app.displayError("System error modifying file:" + t.getMessage());
500 protected void onUnauthorized(Response response) {
501 app.sessionExpired();
504 headFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
505 Scheduler.get().scheduleDeferred(headFile);
509 public void onError(Throwable t) {
511 app.displayError("System error modifying file:" + t.getMessage());
515 protected void onUnauthorized(Response response) {
516 app.sessionExpired();
519 updateFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
521 String readPermHeader = Const.READ_EQ;
522 String writePermHeader = Const.WRITE_EQ;
523 for (String u : newPermissions.keySet()) {
524 Boolean[] p = newPermissions.get(u);
525 if (p[0] != null && p[0]) {
526 readPermHeader += u + Const.COMMA;
528 if (p[1] != null && p[1]) {
529 writePermHeader += u + Const.COMMA;
532 if (readPermHeader.endsWith(Const.EQ)) {
535 else if (readPermHeader.endsWith(Const.COMMA)) {
536 readPermHeader = readPermHeader.substring(0, readPermHeader.length() - 1);
538 if (writePermHeader.endsWith(Const.EQ)) {
539 writePermHeader = "";
541 else if (writePermHeader.endsWith(Const.COMMA)) {
542 writePermHeader = writePermHeader.substring(0, writePermHeader.length() - 1);
544 String permHeader = readPermHeader +
545 ((readPermHeader.length() > 0 && writePermHeader.length() > 0) ? Const.SEMI : "") + writePermHeader;
546 if (permHeader.length() == 0) {
547 permHeader=Const.TILDE;
550 permHeader = URL.encodePathSegment(permHeader);
552 updateFile.setHeader(Const.X_OBJECT_SHARING, permHeader);
553 Scheduler.get().scheduleDeferred(updateFile);
555 else if (!app.isMySharedSelected()) {
556 app.updateFolder(file.getParent(), true, new Command() {
558 public void execute() {
559 if (file.isSharedOrPublished())
560 app.updateMySharedRoot();
565 app.updateSharedFolder(file.getParent(), true);
568 protected void updateMetaDataForPrivateSharing() {
569 updateMetaDataForPrivateSharing(
572 file.getUri() + Const.QUESTION_MARK_UPDATE_EQ,
573 permList.getPermissions()
577 protected void onPreviewNativeEvent(NativePreviewEvent preview) {
578 super.onPreviewNativeEvent(preview);
580 NativeEvent evt = preview.getNativeEvent();
581 if (evt.getType().equals(Const.EVENT_TYPE_KEYDOWN) &&
582 evt.getKeyCode() == KeyCodes.KEY_ENTER) {
589 protected boolean accept() {