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 PermissionsUncheckWarning extends AbstractPropertiesDialog {
63 private PermissionsUncheckWarning(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 PermissionsList permList;
122 public interface PrivateSharingImages extends MessagePanel.Images {
124 @Source("gr/grnet/pithos/resources/edit_user.png")
125 ImageResource permUser();
127 @Source("gr/grnet/pithos/resources/groups22.png")
128 ImageResource permGroup();
130 @Source("gr/grnet/pithos/resources/delete.gif")
131 ImageResource delete();
134 private final File file;
136 private final PrivateSharingImages privateSharingImages = GWT.create(PrivateSharingImages.class);
139 * The widget's constructor.
141 public FileShareDialog(Pithos app, File file) {
145 Anchor close = new Anchor("close");
146 close.addStyleName("close");
147 close.addClickHandler(new ClickHandler() {
150 public void onClick(ClickEvent event) {
154 // Set the dialog's caption.
155 setText(Const.TXT_SHARE_FILE);
156 setGlassEnabled(true);
157 setStyleName("pithos-DialogBox");
159 // Outer contains inner and buttons.
160 final VerticalPanel outer = new VerticalPanel();
162 final FocusPanel focusPanel = new FocusPanel(outer);
163 // Inner contains generalPanel and permPanel.
164 inner = new VerticalPanel();
165 inner.addStyleName("inner");
167 inner.add(createMainPanel());
171 final Button ok = new Button("OK", new ClickHandler() {
173 public void onClick(ClickEvent event) {
177 ok.addStyleName("button");
180 outer.setCellHorizontalAlignment(inner, HasHorizontalAlignment.ALIGN_CENTER);
182 focusPanel.setFocus(true);
186 private boolean IamOwner() {
187 return file.getOwnerID().equals(app.getUserID());
190 private void populatePublicSharingPanel(VerticalPanel publicSharingPanel) {
192 final HorizontalPanel publicCheckPanel = new HorizontalPanel();
193 publicCheckPanel.setSpacing(8);
196 final CheckBox publicCheckBox = new CheckBox();
197 Label publicCheckTitle = new InlineHTML("<b>Public on the Internet</b>");
198 Label publicCheckInfo = new Label("Anyone who has the public link can access. No sign-in required.", true);
200 publicCheckBox.setValue(isFilePubliclyShared());
201 publicCheckBox.addClickHandler(new ClickHandler() {
203 public void onClick(ClickEvent event) {
204 final Boolean published;
205 if(publicCheckBox.getValue() != file.isPublished() && IamOwner()) {
206 published = publicCheckBox.getValue();
209 published = Boolean.FALSE;
212 updateMetaDataForPublicSharing(published);
216 publicCheckPanel.add(publicCheckBox);
217 publicCheckPanel.add(publicCheckTitle);
218 publicCheckPanel.add(publicCheckInfo);
221 publicPathPanel.setVisible(false);
222 publicPathPanel.setWidth(Const.PERCENT_100);
223 publicPathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
224 publicPathPanel.add(new Label(Const.TXT_PUBLIC_LINK));
225 publicPathPanel.setSpacing(8);
226 publicPathPanel.addStyleName("pithos-TabPanelBottom");
228 publicPathText.setWidth(Const.PERCENT_100);
229 publicPathText.addClickHandler(new ClickHandler() {
231 public void onClick(ClickEvent event) {
232 Pithos.enableIESelection();
233 ((TextBox) event.getSource()).selectAll();
234 Pithos.preventIESelection();
238 publicPathText.setText(""); // check: showLinkForPublicSharing();
239 publicPathText.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");
240 publicPathText.setReadOnly(true);
241 publicPathPanel.add(publicPathText);
243 publicSharingPanel.add(publicCheckPanel);
244 publicSharingPanel.add(publicPathPanel);
246 Scheduler.get().scheduleDeferred(new Command() {
248 public void execute() {
249 showLinkForPublicSharing();
255 private void populatePrivateSharingPanel(VerticalPanel privateSharingPanel) {
256 final HorizontalPanel privateCheckPanel = new HorizontalPanel();
257 final VerticalPanel privatePermPanel = new VerticalPanel();
258 final HorizontalPanel permButtons = new HorizontalPanel();
260 privateCheckPanel.setSpacing(8);
261 privatePermPanel.setVisible(isFilePrivatelyShared());
262 permButtons.setSpacing(8);
265 final CheckBox privateCheckBox = new CheckBox();
266 final Label privateCheckTitle = new InlineHTML("<b>Private sharing</b>");
267 final Label privateCheckInfo = new Label("Only people explicitly granted permission can access. Sign-in required.", true);
269 privateCheckBox.setValue(isFilePrivatelyShared());
270 privateCheckBox.addClickHandler(new ClickHandler() {
272 public void onClick(ClickEvent event) {
273 // This is the value *after* the click is applied :)
274 boolean userCheckedIt = privateCheckBox.getValue();
275 boolean userUncheckedIt = !userCheckedIt;
277 if(isFilePrivatelyShared()) {
278 // ignore the click, set it always to "checked"
279 privateCheckBox.setValue(true);
281 privatePermPanel.setVisible(true);
284 if(userUncheckedIt) {
285 new PermissionsUncheckWarning(app).center();
289 privatePermPanel.setVisible(userCheckedIt);
294 privateCheckPanel.add(privateCheckBox);
295 privateCheckPanel.add(privateCheckTitle);
296 privateCheckPanel.add(privateCheckInfo);
299 permList = new PermissionsList(app, privateSharingImages, file.getPermissions(), file.getOwnerID(), false, new Command() {
301 public void execute() {
302 updateMetaDataForPrivateSharing();
306 // Permission Add buttons
307 Button addUser = new Button("Add User", new ClickHandler() {
309 public void onClick(ClickEvent event) {
310 PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, true);
312 permList.updatePermissionTable();
315 addUser.addStyleName("button");
316 permButtons.add(addUser);
318 final boolean haveGroups = app.getAccount().getGroups().size() > 0;
321 Button addGroup = new Button("Add Group", new ClickHandler() {
323 public void onClick(ClickEvent event) {
324 PermissionsAddDialog dlg = new PermissionsAddDialog(app, app.getAccount().getGroups(), permList, false);
326 permList.updatePermissionTable();
329 addGroup.addStyleName("button");
331 permButtons.add(addGroup);
332 permButtons.setCellHorizontalAlignment(addGroup, HasHorizontalAlignment.ALIGN_CENTER);
335 final Button addEverybody = new Button("Add everybody", new ClickHandler() {
337 public void onClick(ClickEvent event) {
338 Pithos.LOG("Adding to Everybody");
340 permList.addPermission("*", true, false);
341 permList.updatePermissionTable();
344 addEverybody.addStyleName("button");
345 permButtons.add(addEverybody);
347 privatePermPanel.add(permList);
348 privatePermPanel.add(permButtons);
351 privatePathPanel.setVisible(false);
352 privatePathPanel.setWidth(Const.PERCENT_100);
353 privatePathPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
354 privatePathPanel.add(new Label(Const.TXT_PRIVATE_LINK));
355 privatePathPanel.setSpacing(8);
356 privatePathPanel.addStyleName("pithos-TabPanelBottom");
358 privatePathText.setWidth(Const.PERCENT_100);
359 privatePathText.addClickHandler(new ClickHandler() {
361 public void onClick(ClickEvent event) {
362 Pithos.enableIESelection();
363 ((TextBox) event.getSource()).selectAll();
364 Pithos.preventIESelection();
368 privatePathText.setText(""); // check: showLinkForPrivateSharing();
369 privatePathText.setTitle("Use this link for sharing the file via e-mail, IM, etc. (crtl-C/cmd-C to copy to system clipboard)");
370 privatePathText.setWidth(Const.PERCENT_100);
371 privatePathText.setReadOnly(true);
372 privatePathPanel.add(privatePathText);
374 Scheduler.get().scheduleDeferred(new Command() {
376 public void execute() {
377 showLinkForPrivateSharing();
381 privateSharingPanel.add(privateCheckPanel);
382 privateSharingPanel.add(privatePermPanel);
383 privateSharingPanel.add(privatePathPanel);
386 private Panel createMainPanel() {
387 VerticalPanel panelAll = new VerticalPanel();
388 VerticalPanel panelPublic = new VerticalPanel();
389 VerticalPanel panelPrivate = new VerticalPanel();
391 populatePrivateSharingPanel(panelPrivate);
392 populatePublicSharingPanel(panelPublic);
394 panelAll.add(panelPrivate);
395 panelAll.add(new InlineHTML("<hr/>"));
396 panelAll.add(panelPublic);
401 private boolean isFilePubliclyShared() {
402 return file.isPublished();
405 private boolean isFilePrivatelyShared() {
406 return file.isShared();
409 private void showLinkForPublicSharing() {
410 if (isFilePubliclyShared()) {
411 // Transitional: When the server returns the full URL in X-Object-Public,
413 final String filePublicURI = file.getPublicUri();
414 final String shownPublicURI;
415 if(filePublicURI.toLowerCase().startsWith("http")) {
416 shownPublicURI = filePublicURI;
419 UrlBuilder b = Window.Location.createUrlBuilder();
420 b.setPath(filePublicURI);
421 shownPublicURI = b.buildString();
424 publicPathText.setText(shownPublicURI);
425 publicPathPanel.setVisible(true);
428 publicPathPanel.setVisible(false);
432 private void showLinkForPrivateSharing() {
433 if (isFilePrivatelyShared()) {
434 final String fileViewURL = Pithos.getFileViewURL(file);
435 final String shownViewURL;
436 if(fileViewURL.toLowerCase().startsWith("http")) {
437 shownViewURL = fileViewURL;
440 UrlBuilder b = Window.Location.createUrlBuilder();
441 b.setPath(fileViewURL);
442 shownViewURL = b.buildString();
445 privatePathText.setText(shownViewURL);
446 privatePathPanel.setVisible(true);
449 privatePathPanel.setVisible(false);
453 protected void updateMetaDataForPublicSharing(String api, String owner, final String path, final Boolean published) {
454 if (published != null) {
455 PostRequest updateFile = new PostRequest(api, owner, path) {
457 public void onSuccess(Resource result) {
458 HeadRequest<File> headFile = new HeadRequest<File>(File.class, Pithos.getStorageAPIURL(), file.getOwnerID(), path, file) {
461 public void onSuccess(File _result) {
462 showLinkForPublicSharing();
463 if (!app.isMySharedSelected()) {
464 app.updateFolder(file.getParent(), true, new Command() {
467 public void execute() {
468 app.updateMySharedRoot();
473 app.updateSharedFolder(file.getParent(), true);
478 public void onError(Throwable t) {
480 app.displayError("System error modifying file:" + t.getMessage());
484 protected void onUnauthorized(Response response) {
485 app.sessionExpired();
488 headFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
489 Scheduler.get().scheduleDeferred(headFile);
493 public void onError(Throwable t) {
495 app.displayError("System error modifying file:" + t.getMessage());
499 protected void onUnauthorized(Response response) {
500 app.sessionExpired();
503 updateFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
504 updateFile.setHeader(Const.X_OBJECT_PUBLIC, published.toString());
505 Scheduler.get().scheduleDeferred(updateFile);
507 else if (!app.isMySharedSelected())
508 app.updateFolder(file.getParent(), true, new Command() {
510 public void execute() {
511 if (file.isSharedOrPublished()) {
512 app.updateMySharedRoot();
517 app.updateSharedFolder(file.getParent(), true);
519 protected void updateMetaDataForPublicSharing(Boolean published) {
520 updateMetaDataForPublicSharing(
521 Pithos.getStorageAPIURL(),
523 file.getUri() + Const.QUESTION_MARK_UPDATE_EQ,
528 protected void updateMetaDataForPrivateSharing(String api, String owner, final String path, final Map<String, Boolean[]> newPermissions) {
529 if (newPermissions != null) {
530 PostRequest updateFile = new PostRequest(api, owner, path) {
532 public void onSuccess(Resource result) {
533 HeadRequest<File> headFile = new HeadRequest<File>(File.class, Pithos.getStorageAPIURL(), file.getOwnerID(), path, file) {
536 public void onSuccess(File _result) {
537 showLinkForPrivateSharing();
538 if (!app.isMySharedSelected())
539 app.updateFolder(file.getParent(), true, new Command() {
542 public void execute() {
543 app.updateMySharedRoot();
547 app.updateSharedFolder(file.getParent(), true);
551 public void onError(Throwable t) {
553 app.displayError("System error modifying file:" + t.getMessage());
557 protected void onUnauthorized(Response response) {
558 app.sessionExpired();
561 headFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
562 Scheduler.get().scheduleDeferred(headFile);
566 public void onError(Throwable t) {
568 app.displayError("System error modifying file:" + t.getMessage());
572 protected void onUnauthorized(Response response) {
573 app.sessionExpired();
576 updateFile.setHeader(Const.X_AUTH_TOKEN, app.getUserToken());
578 String readPermHeader = Const.READ_EQ;
579 String writePermHeader = Const.WRITE_EQ;
580 for (String u : newPermissions.keySet()) {
581 Boolean[] p = newPermissions.get(u);
582 if (p[0] != null && p[0]) {
583 readPermHeader += u + Const.COMMA;
585 if (p[1] != null && p[1]) {
586 writePermHeader += u + Const.COMMA;
589 if (readPermHeader.endsWith(Const.EQ)) {
592 else if (readPermHeader.endsWith(Const.COMMA)) {
593 readPermHeader = readPermHeader.substring(0, readPermHeader.length() - 1);
595 if (writePermHeader.endsWith(Const.EQ)) {
596 writePermHeader = "";
598 else if (writePermHeader.endsWith(Const.COMMA)) {
599 writePermHeader = writePermHeader.substring(0, writePermHeader.length() - 1);
601 String permHeader = readPermHeader +
602 ((readPermHeader.length() > 0 && writePermHeader.length() > 0) ? Const.SEMI : "") + writePermHeader;
603 if (permHeader.length() == 0) {
604 permHeader=Const.TILDE;
607 permHeader = URL.encodePathSegment(permHeader);
609 updateFile.setHeader(Const.X_OBJECT_SHARING, permHeader);
610 Scheduler.get().scheduleDeferred(updateFile);
612 else if (!app.isMySharedSelected()) {
613 app.updateFolder(file.getParent(), true, new Command() {
615 public void execute() {
616 if (file.isSharedOrPublished())
617 app.updateMySharedRoot();
622 app.updateSharedFolder(file.getParent(), true);
625 protected void updateMetaDataForPrivateSharing() {
626 updateMetaDataForPrivateSharing(
627 Pithos.getStorageAPIURL(),
629 file.getUri() + Const.QUESTION_MARK_UPDATE_EQ,
630 permList.getPermissions()
635 protected void onPreviewNativeEvent(NativePreviewEvent preview) {
636 super.onPreviewNativeEvent(preview);
638 NativeEvent evt = preview.getNativeEvent();
639 if (evt.getType().equals(Const.EVENT_TYPE_KEYDOWN) &&
640 evt.getKeyCode() == KeyCodes.KEY_ENTER) {
647 protected boolean accept() {