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 {
62 private static final class PremissionsUncheckWarning extends AbstractPropertiesDialog {
63 private PremissionsUncheckWarning(Pithos app) {
65 final Anchor close = new Anchor("close");
66 close.addStyleName("close");
67 close.addClickHandler(new ClickHandler() {
69 public void onClick(ClickEvent event) {
73 final String dialogText = "Info";
75 setStyleName("pithos-DialogBox");
77 final VerticalPanel panel = new VerticalPanel();
80 VerticalPanel inner = new VerticalPanel();
81 inner.addStyleName("inner");
85 "It seems you are already sharing this file with some users." +
87 "Please remove all users from the sharing list, to be able to uncheck this option."
91 final Button ok = new Button("OK", new ClickHandler() {
93 public void onClick(ClickEvent event) {
98 ok.addStyleName("button");
102 panel.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);
108 protected boolean accept() {
113 // For public sharing
114 private final HorizontalPanel publicPathPanel = new HorizontalPanel();
115 private final TextBox publicPathText = new TextBox();
117 // For private sharing
118 private final HorizontalPanel privatePathPanel = new HorizontalPanel();
119 private final TextBox privatePathText = new TextBox();
120 private final VerticalPanel privatePermSuperPanel = new VerticalPanel();
121 private PermissionsList permList;
124 * An image bundle for this widgets images.
126 public interface PublicSharingImages extends MessagePanel.Images {
128 @Source("gr/grnet/pithos/resources/edit_user.png")
129 ImageResource permUser();
131 @Source("gr/grnet/pithos/resources/groups22.png")
132 ImageResource permGroup();
134 @Source("gr/grnet/pithos/resources/editdelete.png")
135 ImageResource delete();
138 public interface PrivateSharingImages extends MessagePanel.Images {
140 @Source("gr/grnet/pithos/resources/edit_user.png")
141 ImageResource permUser();
143 @Source("gr/grnet/pithos/resources/groups22.png")
144 ImageResource permGroup();
146 @Source("gr/grnet/pithos/resources/delete.gif")
147 ImageResource delete();
150 private final File file;
152 private final PublicSharingImages publicSharingImages = GWT.create(PublicSharingImages.class);
153 private final PrivateSharingImages privateSharingImages = GWT.create(PrivateSharingImages.class);
156 * The widget's constructor.
158 public FileShareDialog(Pithos app, File file) {
162 Anchor close = new Anchor("close");
163 close.addStyleName("close");
164 close.addClickHandler(new ClickHandler() {
167 public void onClick(ClickEvent event) {
171 // Set the dialog's caption.
172 setText(Const.TXT_SHARE_FILE);
173 setGlassEnabled(true);
174 setStyleName("pithos-DialogBox");
176 // Outer contains inner and buttons.
177 final VerticalPanel outer = new VerticalPanel();
179 final FocusPanel focusPanel = new FocusPanel(outer);
180 // Inner contains generalPanel and permPanel.
181 inner = new VerticalPanel();
182 inner.addStyleName("inner");
184 inner.add(createMainPanel());
188 final Button ok = new Button("OK", new ClickHandler() {
190 public void onClick(ClickEvent event) {
194 ok.addStyleName("button");
197 outer.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);
199 focusPanel.setFocus(true);
203 private boolean IamOwner() {
204 return file.getOwnerID().equals(app.getUserID());
207 private void populatePublicSharingPanel(VerticalPanel publicSharingPanel) {
209 final HorizontalPanel publicCheckPanel = new HorizontalPanel();
210 publicCheckPanel.setSpacing(8);
213 final CheckBox publicCheckBox = new CheckBox();
214 Label publicCheckTitle = new InlineHTML("<b>Public on the Internet</b>");
215 Label publicCheckInfo = new Label("Anyone who has the public link can access. No sign-in required.", true);
217 publicCheckBox.setValue(isFilePubliclyShared());
218 publicCheckBox.addClickHandler(new ClickHandler() {
220 public void onClick(ClickEvent event) {
221 final Boolean published;
222 if(publicCheckBox.getValue() != file.isPublished() && IamOwner()) {
223 published = publicCheckBox.getValue();
226 published = Boolean.FALSE;
229 updateMetaDataForPublicSharing(published);
233 publicCheckPanel.add(publicCheckBox);
234 publicCheckPanel.add(publicCheckTitle);
235 publicCheckPanel.add(publicCheckInfo);
238 publicPathPanel.setVisible(false);
239 publicPathPanel.setWidth(Const.PERCENT_100);
240 publicPathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
241 publicPathPanel.add(new Label(Const.TXT_PUBLIC_LINK));
242 publicPathPanel.setSpacing(8);
243 publicPathPanel.addStyleName("pithos-TabPanelBottom");
245 publicPathText.setWidth(Const.PERCENT_100);
246 publicPathText.addClickHandler(new ClickHandler() {
248 public void onClick(ClickEvent event) {
249 Pithos.enableIESelection();
250 ((TextBox) event.getSource()).selectAll();
251 Pithos.preventIESelection();
254 publicPathText.setText(Window.Location.getHost() + file.getPublicUri());
255 publicPathText.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");
256 publicPathText.setReadOnly(true);
257 publicPathPanel.add(publicPathText);
259 publicSharingPanel.add(publicCheckPanel);
260 publicSharingPanel.add(publicPathPanel);
262 Scheduler.get().scheduleDeferred(new Command() {
264 public void execute() {
265 showLinkForPublicSharing();
271 private void populatePrivateSharingPanel(VerticalPanel privateSharingPanel) {
272 final HorizontalPanel privateCheckPanel = new HorizontalPanel();
273 final VerticalPanel privatePermPanel = new VerticalPanel();
274 final HorizontalPanel permButtons = new HorizontalPanel();
276 privateCheckPanel.setSpacing(8);
277 privatePermPanel.setVisible(isFilePrivatelyShared());
278 permButtons.setSpacing(8);
281 final CheckBox privateCheckBox = new CheckBox();
282 final Label privateCheckTitle = new InlineHTML("<b>Private sharing</b>");
283 final Label privateCheckInfo = new Label("Only people explicitly granted permission can access. Sign-in required.", true);
285 privateCheckBox.setValue(isFilePrivatelyShared());
286 privateCheckBox.addClickHandler(new ClickHandler() {
288 public void onClick(ClickEvent event) {
289 // This is the value *after* the click is applied :)
290 boolean userCheckedIt = privateCheckBox.getValue();
291 boolean userUncheckedIt = !userCheckedIt;
293 if(isFilePrivatelyShared()) {
294 // ignore the click, set it always to "checked"
295 privateCheckBox.setValue(true);
297 privatePermPanel.setVisible(true);
300 if(userUncheckedIt) {
301 new PremissionsUncheckWarning(app).center();
305 privatePermPanel.setVisible(userCheckedIt);
310 privateCheckPanel.add(privateCheckBox);
311 privateCheckPanel.add(privateCheckTitle);
312 privateCheckPanel.add(privateCheckInfo);
315 permList = new PermissionsList(app, privateSharingImages, file.getPermissions(), file.getOwnerID(), false, new Command() {
317 public void execute() {
318 updateMetaDataForPrivateSharing();
322 // Permission Add buttons
323 Button addUser = new Button("Add User", new ClickHandler() {
325 public void onClick(ClickEvent event) {
326 PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, true);
328 permList.updatePermissionTable();
331 addUser.addStyleName("button");
332 permButtons.add(addUser);
334 final boolean haveGroups = app.getAccount().getGroups().size() > 0;
337 Button addGroup = new Button("Add Group", new ClickHandler() {
339 public void onClick(ClickEvent event) {
340 PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, false);
342 permList.updatePermissionTable();
345 addGroup.addStyleName("button");
347 permButtons.add(addGroup);
348 permButtons.setCellHorizontalAlignment(addGroup, HasHorizontalAlignment.ALIGN_CENTER);
351 final Button addEverybody = new Button("Add everybody", new ClickHandler() {
353 public void onClick(ClickEvent event) {
354 Pithos.LOG("Adding to Everybody");
356 permList.addPermission("*", true, false);
357 permList.updatePermissionTable();
360 addEverybody.addStyleName("button");
361 permButtons.add(addEverybody);
363 privatePermPanel.add(permList);
364 privatePermPanel.add(permButtons);
367 privatePathPanel.setVisible(false);
368 privatePathPanel.setWidth(Const.PERCENT_100);
369 privatePathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
370 privatePathPanel.add(new Label(Const.TXT_PRIVATE_LINK));
371 privatePathPanel.setSpacing(8);
372 privatePathPanel.addStyleName("pithos-TabPanelBottom");
374 privatePathText.setWidth(Const.PERCENT_100);
375 privatePathText.addClickHandler(new ClickHandler() {
377 public void onClick(ClickEvent event) {
378 Pithos.enableIESelection();
379 ((TextBox) event.getSource()).selectAll();
380 Pithos.preventIESelection();
383 privatePathText.setText(Window.Location.getHost() + file.getPublicUri());
384 privatePathText.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");
385 privatePathText.setWidth(Const.PERCENT_100);
386 privatePathText.setReadOnly(true);
387 privatePathPanel.add(privatePathText);
389 Scheduler.get().scheduleDeferred(new Command() {
391 public void execute() {
392 showLinkForPrivateSharing();
396 privateSharingPanel.add(privateCheckPanel);
397 privateSharingPanel.add(privatePermPanel);
398 privateSharingPanel.add(privatePathPanel);
401 private Panel createMainPanel() {
402 VerticalPanel panelAll = new VerticalPanel();
403 VerticalPanel panelPublic = new VerticalPanel();
404 VerticalPanel panelPrivate = new VerticalPanel();
406 populatePrivateSharingPanel(panelPrivate);
407 populatePublicSharingPanel(panelPublic);
409 panelAll.add(panelPrivate);
410 panelAll.add(new InlineHTML("<hr/>"));
411 panelAll.add(panelPublic);
416 private boolean isFilePubliclyShared() {
417 return file.isPublished();
420 private boolean isFilePrivatelyShared() {
421 return file.isShared();
424 private void showLinkForPublicSharing() {
425 if (isFilePubliclyShared()) {
426 UrlBuilder b = Window.Location.createUrlBuilder();
427 b.setPath(file.getPublicUri());
428 publicPathText.setText(b.buildString());
429 publicPathPanel.setVisible(true);
432 publicPathPanel.setVisible(false);
436 private void showLinkForPrivateSharing() {
437 if (isFilePrivatelyShared()) {
438 UrlBuilder b = Window.Location.createUrlBuilder();
439 b.setPath(Pithos.getStorageAPIURL() + file.getOwnerID() + file.getUri());
440 String href = Window.Location.getHref();
441 boolean hasParameters = href.contains(Const.QUESTION_MARK);
442 privatePathText.setText(href + (hasParameters ? Const.AMPERSAND : Const.QUESTION_MARK) + Const.GOTO_EQ + b.buildString());
443 privatePathPanel.setVisible(true);
446 privatePathPanel.setVisible(false);
450 protected void updateMetaDataForPublicSharing(String api, String owner, final String path, final Boolean published) {
451 if (published != null) {
452 PostRequest updateFile = new PostRequest(api, owner, path) {
454 public void onSuccess(Resource result) {
455 HeadRequest<File> headFile = new HeadRequest<File>(File.class, Pithos.getStorageAPIURL(), file.getOwnerID(), path, file) {
458 public void onSuccess(File _result) {
459 showLinkForPublicSharing();
460 if (!app.isMySharedSelected()) {
461 app.updateFolder(file.getParent(), true, new Command() {
464 public void execute() {
465 app.updateMySharedRoot();
470 app.updateSharedFolder(file.getParent(), true);
475 public void onError(Throwable t) {
477 app.displayError("System error modifying file:" + t.getMessage());
481 protected void onUnauthorized(Response response) {
482 app.sessionExpired();
485 headFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
486 Scheduler.get().scheduleDeferred(headFile);
490 public void onError(Throwable t) {
492 app.displayError("System error modifying file:" + t.getMessage());
496 protected void onUnauthorized(Response response) {
497 app.sessionExpired();
500 updateFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
501 updateFile.setHeader(Const.X_OBJECT_PUBLIC, published.toString());
502 Scheduler.get().scheduleDeferred(updateFile);
504 else if (!app.isMySharedSelected())
505 app.updateFolder(file.getParent(), true, new Command() {
507 public void execute() {
508 if (file.isSharedOrPublished()) {
509 app.updateMySharedRoot();
514 app.updateSharedFolder(file.getParent(), true);
516 protected void updateMetaDataForPublicSharing(Boolean published) {
517 updateMetaDataForPublicSharing(
518 Pithos.getStorageAPIURL(),
520 file.getUri() + Const.QUESTION_MARK_UPDATE_EQ,
525 protected void updateMetaDataForPrivateSharing(String api, String owner, final String path, final Map<String, Boolean[]> newPermissions) {
526 if (newPermissions != null) {
527 PostRequest updateFile = new PostRequest(api, owner, path) {
529 public void onSuccess(Resource result) {
530 HeadRequest<File> headFile = new HeadRequest<File>(File.class, Pithos.getStorageAPIURL(), file.getOwnerID(), path, file) {
533 public void onSuccess(File _result) {
534 showLinkForPrivateSharing();
535 if (!app.isMySharedSelected())
536 app.updateFolder(file.getParent(), true, new Command() {
539 public void execute() {
540 app.updateMySharedRoot();
544 app.updateSharedFolder(file.getParent(), true);
548 public void onError(Throwable t) {
550 app.displayError("System error modifying file:" + t.getMessage());
554 protected void onUnauthorized(Response response) {
555 app.sessionExpired();
558 headFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
559 Scheduler.get().scheduleDeferred(headFile);
563 public void onError(Throwable t) {
565 app.displayError("System error modifying file:" + t.getMessage());
569 protected void onUnauthorized(Response response) {
570 app.sessionExpired();
573 updateFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
575 String readPermHeader = Const.READ_EQ;
576 String writePermHeader = Const.WRITE_EQ;
577 for (String u : newPermissions.keySet()) {
578 Boolean[] p = newPermissions.get(u);
579 if (p[0] != null && p[0]) {
580 readPermHeader += u + Const.COMMA;
582 if (p[1] != null && p[1]) {
583 writePermHeader += u + Const.COMMA;
586 if (readPermHeader.endsWith(Const.EQ)) {
589 else if (readPermHeader.endsWith(Const.COMMA)) {
590 readPermHeader = readPermHeader.substring(0, readPermHeader.length() - 1);
592 if (writePermHeader.endsWith(Const.EQ)) {
593 writePermHeader = "";
595 else if (writePermHeader.endsWith(Const.COMMA)) {
596 writePermHeader = writePermHeader.substring(0, writePermHeader.length() - 1);
598 String permHeader = readPermHeader +
599 ((readPermHeader.length() > 0 && writePermHeader.length() > 0) ? Const.SEMI : "") + writePermHeader;
600 if (permHeader.length() == 0) {
601 permHeader=Const.TILDE;
604 permHeader = URL.encodePathSegment(permHeader);
606 updateFile.setHeader(Const.X_OBJECT_SHARING, permHeader);
607 Scheduler.get().scheduleDeferred(updateFile);
609 else if (!app.isMySharedSelected()) {
610 app.updateFolder(file.getParent(), true, new Command() {
612 public void execute() {
613 if (file.isSharedOrPublished())
614 app.updateMySharedRoot();
619 app.updateSharedFolder(file.getParent(), true);
622 protected void updateMetaDataForPrivateSharing() {
623 updateMetaDataForPrivateSharing(
624 Pithos.getStorageAPIURL(),
626 file.getUri() + Const.QUESTION_MARK_UPDATE_EQ,
627 permList.getPermissions()
632 protected void onPreviewNativeEvent(NativePreviewEvent preview) {
633 super.onPreviewNativeEvent(preview);
635 NativeEvent evt = preview.getNativeEvent();
636 if (evt.getType().equals(Const.EVENT_TYPE_KEYDOWN) &&
637 evt.getKeyCode() == KeyCodes.KEY_ENTER) {
644 protected boolean accept() {