diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b5e25..ddbc747 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,21 +4,31 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v6.31.0-SNAPSHOT] [r4.25.0] - 2020-07-16 + +#### Enhancements + +[#19600] revisit the "Get Info" Dialog in a modern view + +#### New Features + +[#19695] Show the file preview via Google Docs Viewer + ## [v6.30.1] [r4.24.0] - 2020-06-25 -**Fixes** +#### Fixes -[Task #19544] update the unsharing messages in the accounting history +[#19544] update the unsharing messages in the accounting history ## [v6.30.0] [r4.23.0] - 2020-05-18 -**New Features** +#### New Features [#19058] Restore operation: the user has to select the destination folder -**Fixes** +#### Fixes [#19232] Fixed upload of file names that use special characters @@ -27,7 +37,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [v6.29.0] [r4.21.0] - 2020-03-27 -**New Features** +#### New Features [#18150] Get Shareable Link as Long URL also @@ -35,7 +45,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm [#18174] Workspace Search facility, business logic applied on workspace side -**Fixes** +#### Fixes [#18577] Fixing Shareable link informative text for public file diff --git a/pom.xml b/pom.xml index 9851010..6e9d4f9 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.gcube.portlets.user workspace-tree-widget - 6.30.1 + 6.31.0-SNAPSHOT gCube Workspace Tree Widget gCube Workspace Tree Widget is a widget to navigate and interact with gCube Workspace @@ -180,7 +180,7 @@ org.gcube.portlets.widgets ws-task-executor-widget - [0.0.1, 2.0.0-SNAPSHOT) + [0.0.1, 1.0.0-SNAPSHOT) @@ -218,7 +218,7 @@ org.gcube.common storagehub-client-wrapper - [0.6.2, 1.0.0-SNAPSHOT) + [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT) compile diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/AppControllerExplorer.java b/src/main/java/org/gcube/portlets/user/workspace/client/AppControllerExplorer.java index 2a6bd5b..72a5d34 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/AppControllerExplorer.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/AppControllerExplorer.java @@ -118,7 +118,6 @@ import org.gcube.portlets.user.workspace.client.view.tree.AsyncTreePanel; import org.gcube.portlets.user.workspace.client.view.windows.DialogAddFolderAndSmart; import org.gcube.portlets.user.workspace.client.view.windows.DialogAddFolderAndSmart.AddType; import org.gcube.portlets.user.workspace.client.view.windows.DialogAddUrl; -import org.gcube.portlets.user.workspace.client.view.windows.DialogGetInfo; import org.gcube.portlets.user.workspace.client.view.windows.DialogGetLink; import org.gcube.portlets.user.workspace.client.view.windows.DialogGetLink.Link_Type; import org.gcube.portlets.user.workspace.client.view.windows.DialogShareLink; @@ -209,6 +208,8 @@ public class AppControllerExplorer implements EventHandler, TreeAppControllerInt private WsTaskExecutorWidget taskExecutor = new WsTaskExecutorWidget(); public static final int delayTime = 3000; + + public static Map> mapOfAllowedMimeTypesForPreview = null; /** * Instantiates a new app controller explorer. @@ -690,8 +691,35 @@ public class AppControllerExplorer implements EventHandler, TreeAppControllerInt @Override public void onGetInfo(GetInfoEvent getInfoEvent) { - new DialogGetInfo(getInfoEvent.getSourceFile()); - //new DialogInfoboot(getInfoEvent.getSourceFile()); + //new DialogGetInfo(getInfoEvent.getSourceFile()); + + final FileModel fileItem = getInfoEvent.getSourceFile(); + + if(fileItem!=null) { + /*final Modal modal = new Modal(true); + modal.setCloseVisible(true); + modal.setTitle(fileItem.getName() + " - Details"); + modal.setMaxHeigth("800px"); + + ModalFooter modalFooter = new ModalFooter(); + final Button buttClose = new Button("Close"); + modalFooter.add(buttClose); + + buttClose.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + modal.hide(); + } + }); + + DialogGetInfoBootstrap dlg = new DialogGetInfoBootstrap(fileItem); + modal.add(dlg); + modal.add(modalFooter); + modal.show();*/ + + notifySubscriber(new GetInfoEvent(fileItem)); + } } }); @@ -2102,6 +2130,9 @@ public class AppControllerExplorer implements EventHandler, TreeAppControllerInt } else if (event instanceof LoadFolderEvent) { LoadFolderEvent loadFolderEvent = (LoadFolderEvent) event; sub.loadFolder(loadFolderEvent.getTargetFolder()); + } else if (event instanceof GetInfoEvent) { + GetInfoEvent getInfoEvent = (GetInfoEvent) event; + sub.showDetails(getInfoEvent.getSourceFile(), mapOfAllowedMimeTypesForPreview); } } @@ -2297,6 +2328,7 @@ public class AppControllerExplorer implements EventHandler, TreeAppControllerInt this.explorerPanel = new ExplorerPanel(true, true); loadMyLogin(); loadMyFirstName(); + loadAllowedMimeTypesForPreview(); return this.explorerPanel; } @@ -2318,9 +2350,12 @@ public class AppControllerExplorer implements EventHandler, TreeAppControllerInt this.selectRootItem = selectRootItem; loadMyLogin(); loadMyFirstName(); + loadAllowedMimeTypesForPreview(); return this.explorerPanel; } + + /** * Edi permissions. * @@ -2604,6 +2639,22 @@ public class AppControllerExplorer implements EventHandler, TreeAppControllerInt } }); } + + private void loadAllowedMimeTypesForPreview() { + + rpcWorkspaceService.getAllowedMimetypesForPreview(new AsyncCallback>>() { + + @Override + public void onFailure(Throwable caught) { + } + + @Override + public void onSuccess(Map> result) { + + mapOfAllowedMimeTypesForPreview = result; + } + }); + } /** * Load my first name. diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/event/GetInfoEvent.java b/src/main/java/org/gcube/portlets/user/workspace/client/event/GetInfoEvent.java index 77da379..7e2697e 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/event/GetInfoEvent.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/event/GetInfoEvent.java @@ -1,5 +1,7 @@ package org.gcube.portlets.user.workspace.client.event; +import org.gcube.portlets.user.workspace.client.interfaces.EventsTypeEnum; +import org.gcube.portlets.user.workspace.client.interfaces.GuiEventInterface; import org.gcube.portlets.user.workspace.client.model.FileModel; import com.google.gwt.event.shared.GwtEvent; @@ -9,7 +11,7 @@ import com.google.gwt.event.shared.GwtEvent; * @author Francesco Mangiacrapa francesco.mangiacrapa{@literal @}isti.cnr.it * */ -public class GetInfoEvent extends GwtEvent { +public class GetInfoEvent extends GwtEvent implements GuiEventInterface{ public static Type TYPE = new Type(); private FileModel targetFile = null; @@ -32,4 +34,9 @@ public class GetInfoEvent extends GwtEvent { public FileModel getSourceFile() { return targetFile; } + + @Override + public EventsTypeEnum getKey() { + return EventsTypeEnum.GET_DETAILS_FOR_ITEM; + } } \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/EventsTypeEnum.java b/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/EventsTypeEnum.java index 10b8892..af1ec47 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/EventsTypeEnum.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/EventsTypeEnum.java @@ -35,5 +35,6 @@ public enum EventsTypeEnum UPDATE_WORKSPACE_SIZE, ADD_ADMINISTRATOR_EVENT, FILE_VERSIONING_HISTORY_EVENT, + GET_DETAILS_FOR_ITEM, LOAD_FOLDER_EVENT; } \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/SubscriberInterface.java b/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/SubscriberInterface.java index 7e50191..b14bd92 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/SubscriberInterface.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/interfaces/SubscriberInterface.java @@ -2,6 +2,7 @@ package org.gcube.portlets.user.workspace.client.interfaces; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.gcube.portlets.user.workspace.client.ConstantsExplorer.ViewSwitchType; import org.gcube.portlets.user.workspace.client.ConstantsExplorer.WS_UPLOAD_TYPE; @@ -10,6 +11,7 @@ import org.gcube.portlets.user.workspace.client.model.FolderModel; import org.gcube.portlets.user.workspace.shared.WorkspaceTrashOperation; +// TODO: Auto-generated Javadoc // Implements this interface to receive events by tree async /** * The Interface SubscriberInterface. @@ -196,5 +198,16 @@ public interface SubscriberInterface { * @param folderTarget the folder target */ void loadFolder(FileModel folderTarget); + + + + /** + * Show details. + * + * @param fileModel the file model + * @param mapAllowedMimeTypesForPreview the map allowed mime types for preview + */ + void showDetails(FileModel fileModel, Map> mapAllowedMimeTypesForPreview); + } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java index de6ec65..9c29f9d 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Icons.java @@ -417,8 +417,9 @@ public interface Icons extends ClientBundle { @Source("icons/sync-icon-synched.png") ImageResource syncIconSynched(); - - + + @Source("icons/no-preview-available.png") + ImageResource previewNotAvailable(); } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java index 930e967..b506b1d 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/resources/Resources.java @@ -7,6 +7,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.AbstractImagePrototype; +// TODO: Auto-generated Javadoc /** * The Class Resources. * @@ -1248,15 +1249,30 @@ public class Resources { } + /** + * Gets the icon sync to. + * + * @return the icon sync to + */ public static AbstractImagePrototype getIconSyncTo() { return AbstractImagePrototype.create(ICONS.syncIconTo()); } + /** + * Gets the icon sync from. + * + * @return the icon sync from + */ public static AbstractImagePrototype getIconSyncFrom() { return AbstractImagePrototype.create(ICONS.syncIconFrom()); } + /** + * Gets the icon synched. + * + * @return the icon synched + */ public static AbstractImagePrototype getIconSynched() { return AbstractImagePrototype.create(ICONS.syncIconSynched()); } @@ -1344,6 +1360,17 @@ public class Resources { public static ImageResource getImageAttachs() { return ICONS.attach(); } + + + /** + * Gets the preview not available. + * + * @return the preview not available + */ + public static ImageResource getPreviewNotAvailable() { + return ICONS.previewNotAvailable(); + } + /** * Gets the icon by media type name. @@ -1503,10 +1530,4 @@ public class Resources { return null; } - - - - - - } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/no-preview-available.png b/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/no-preview-available.png new file mode 100644 index 0000000..9e324b0 Binary files /dev/null and b/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/no-preview-available.png differ diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/preview-not-available.png b/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/preview-not-available.png new file mode 100644 index 0000000..ec57723 Binary files /dev/null and b/src/main/java/org/gcube/portlets/user/workspace/client/resources/icons/preview-not-available.png differ diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceService.java b/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceService.java index 7ea5780..a094c18 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceService.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceService.java @@ -28,6 +28,7 @@ import org.gcube.portlets.user.workspace.shared.accounting.GxtAccountingField; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; +// TODO: Auto-generated Javadoc /** * The Interface GWTWorkspaceService. * @@ -676,4 +677,22 @@ public interface GWTWorkspaceService extends RemoteService { */ FileModel getItemForFileTree(String itemId) throws Exception; + + /** + * Update description for item. + * + * @param itemId the item id + * @param newDescription the new description + * @return the description updated on the server + * @throws Exception the exception + */ + String updateDescriptionForItem(String itemId, String newDescription) throws Exception; + + /** + * Gets the allowed mimetypes for preview. + * + * @return the allowed mimetypes for preview + */ + Map> getAllowedMimetypesForPreview(); + } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceServiceAsync.java b/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceServiceAsync.java index f040300..2f236c4 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceServiceAsync.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/rpc/GWTWorkspaceServiceAsync.java @@ -612,5 +612,24 @@ public interface GWTWorkspaceServiceAsync { * @return the link for send to switch board */ void getLinkForSendToSwitchBoard(String itemId, AsyncCallback callback); + + + /** + * Update description for item. + * + * @param itemId the item id + * @param newDescription the new description + * @param callback the callback + */ + void updateDescriptionForItem(String itemId, String newDescription, AsyncCallback callback); + + + + /** + * Gets the allowed mimetypes for preview. + * + * @return the allowed mimetypes for preview + */ + void getAllowedMimetypesForPreview(AsyncCallback>> callback); } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogEditProperties.java b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogEditProperties.java index 43edd4b..f880474 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogEditProperties.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogEditProperties.java @@ -31,8 +31,8 @@ import com.google.gwt.user.client.rpc.AsyncCallback; public class DialogEditProperties extends Dialog { private FileModel item; - private int widthDialog = 450; - private int heigthDialog = 300; + private int widthDialog = 800; + private int heigthDialog = 400; private Command commad; private List> fields; private FormLayout layout; @@ -50,8 +50,8 @@ public class DialogEditProperties extends Dialog { this.commad = command; layout = new FormLayout(); - layout.setLabelWidth(90); - layout.setDefaultWidth(300); + layout.setLabelWidth(200); + layout.setDefaultWidth(550); setLayout(layout); setHeading("Edit Properties: " + item.getName()); @@ -72,6 +72,15 @@ public class DialogEditProperties extends Dialog { saveProperties(true); } }); + + //SET TOGGLE BUTTON GRID VIEW + /*Scheduler.get().scheduleDeferred(new ScheduledCommand() { + + @Override + public void execute() { + setZIndex(99999); + } + });*/ } /* @@ -82,7 +91,7 @@ public class DialogEditProperties extends Dialog { @Override public void show() { resetForm(); - loadGcubeItemProperties(); + //loadGcubeItemProperties(); super.show(); } @@ -121,31 +130,33 @@ public class DialogEditProperties extends Dialog { } - private void loadGcubeItemProperties() { - // mask("Loading properties..."); - AppControllerExplorer.rpcWorkspaceService.loadGcubeItemProperties(item.getIdentifier(), - new AsyncCallback>() { - - @Override - public void onSuccess(Map result) { - // unmask(); - setProperties(result); - } - - @Override - public void onFailure(Throwable caught) { - // unmask(); - GWT.log("an error occured in loadGcubeItemProperties " + item + " " + caught.getMessage()); - } - }); - } - - private void setProperties(Map result) { +// private void loadGcubeItemProperties() { +// // mask("Loading properties..."); +// AppControllerExplorer.rpcWorkspaceService.loadGcubeItemProperties(item.getIdentifier(), +// new AsyncCallback>() { +// +// @Override +// public void onSuccess(Map result) { +// // unmask(); +// setProperties(result); +// } +// +// @Override +// public void onFailure(Throwable caught) { +// // unmask(); +// GWT.log("an error occured in loadGcubeItemProperties " + item + " " + caught.getMessage()); +// } +// }); +// } + + public void setProperties(Map result) { fields = new ArrayList>(result.size()); for (String key : result.keySet()) { TextField field = new TextField(); + GWT.log("Adding field: "+key); field.setFieldLabel(key); field.setValue(result.get(key)); + field.setReadOnly(false); add(field); fields.add(field); } diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java new file mode 100644 index 0000000..6a5125c --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.java @@ -0,0 +1,900 @@ +package org.gcube.portlets.user.workspace.client.view.windows; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.gcube.portlets.user.workspace.client.AppControllerExplorer; +import org.gcube.portlets.user.workspace.client.ConstantsExplorer; +import org.gcube.portlets.user.workspace.client.event.CreateSharedFolderEvent; +import org.gcube.portlets.user.workspace.client.event.FileDownloadEvent; +import org.gcube.portlets.user.workspace.client.event.FileDownloadEvent.DownloadType; +import org.gcube.portlets.user.workspace.client.interfaces.GXTFolderItemTypeEnum; +import org.gcube.portlets.user.workspace.client.model.FileGridModel; +import org.gcube.portlets.user.workspace.client.model.FileModel; +import org.gcube.portlets.user.workspace.client.resources.Resources; +import org.gcube.portlets.user.workspace.client.workspace.GWTWorkspaceItem; +import org.gcube.portlets.user.workspace.client.workspace.folder.item.GWTExternalImage; +import org.gcube.portlets.user.workspace.client.workspace.folder.item.gcube.GWTImageDocument; +import org.gcube.portlets.user.workspace.shared.PublicLink; +import org.gcube.portlets.widgets.workspacesharingwidget.client.rpc.WorkspaceSharingServiceAsync; + +import com.github.gwtbootstrap.client.ui.Button; +import com.github.gwtbootstrap.client.ui.ControlGroup; +import com.github.gwtbootstrap.client.ui.Label; +import com.github.gwtbootstrap.client.ui.TextArea; +import com.github.gwtbootstrap.client.ui.Tooltip; +import com.github.gwtbootstrap.client.ui.constants.ButtonType; +import com.github.gwtbootstrap.client.ui.constants.IconType; +import com.github.gwtbootstrap.client.ui.constants.LabelType; +import com.github.gwtbootstrap.client.ui.constants.ResizeType; +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style.Float; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.LoadEvent; +import com.google.gwt.event.dom.client.LoadHandler; +import com.google.gwt.http.client.URL; +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.i18n.client.NumberFormat; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Frame; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.NamedFrame; +import com.google.gwt.user.client.ui.Widget; + +// TODO: Auto-generated Javadoc +/** + * The Class DialogGetInfoBootstrap. + * + * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) + * Jul 13, 2020 + */ +public class DialogGetInfoBootstrap extends Composite { + + private static final int PREVIEW_WAITING_TIME = 9000; //9 sec + + private static DialogGetInfoBootstrapUiBinder uiBinder = GWT.create(DialogGetInfoBootstrapUiBinder.class); + + /** + * The Interface DialogGetInfoBootstrapUiBinder. + * + * @author Francesco Mangiacrapa at ISTI-CNR Pisa (Italy) + * Jul 13, 2020 + */ + interface DialogGetInfoBootstrapUiBinder extends UiBinder { + } + + public static final String EMPTY = "empty"; + + private final NumberFormat number = ConstantsExplorer.numberFormatterKB; + + /** + * Instantiates a new dialog get info bootstrap. + */ + public DialogGetInfoBootstrap() { + initWidget(uiBinder.createAndBindUi(this)); + } + + public static final String NOT_AVAILABLE = "n.a."; + + private Map gCubeProperties; + + @UiField + HorizontalPanel hpItemType; + + @UiField + HorizontalPanel hpHeaderDetails; + + @UiField + Button buttonClose; + + @UiField + HTMLPanel htmlPanelImagePreview; + + @UiField + HTMLPanel htmlPanelFilePreview; + + @UiField + HTML txtName; + + @UiField + HTML txtId; + + @UiField + HTML txtLocation; + + @UiField + ControlGroup cgTxtIsPublic; + + @UiField + HTML txtIsPublic; + + @UiField + HTML txtMimeType; + + @UiField + ControlGroup cgTxtMimeType; + + @UiField + ControlGroup cgThreddsSynched; + + @UiField + HTML txtThreddsSynched; + + @UiField + ControlGroup cgGcubeProperties; + + @UiField + TextArea txtAreaGcubeProperties; + + @UiField + TextArea txtAreaDescription; + + @UiField + HTML txtOwner; + + @UiField + HTML txtCreated; + + @UiField + HTML txtLastMofication; + + @UiField + HTML txtSize; + + @UiField + HTML txtShared; + + @UiField + Button buttonUpdateDescription; + + @UiField + Button buttonSaveDescription; + + @UiField + Button buttonUpdateGcubeProperties; + + @UiField + Button buttonUpdateShare; + + @UiField + ControlGroup cgSharedWith; + + @UiField + HTML txtSharedWith; + + private FileModel fileModel; + + private Command onCloseCommand; + + private Tooltip tooltipDownload = new Tooltip("Download"); + + private Button buttonDownload = new Button("Download"); + +// private Tooltip tooltipSharebleLink = new Tooltip("Get Shareable Link"); +// private Button buttonShareableLink = new Button(); + + private DateTimeFormat dateFormatter = DateTimeFormat.getFormat("dd MMM yyyy, hh:mm aaa"); + + private boolean iFrameGoogleDocViewerLoaded = false; + + private Long fileSize = null; + + private Map> mapAllowedMimeTypesForPreview; + + private Image spinnerImage = Resources.getIconLoading().createImage(); + + private Image noPreviewAvailable = new Image(Resources.getPreviewNotAvailable()); + + private Frame iFrameGDV = null; + + private Timer timerGDV = null; + + /** + * Instantiates a new dialog get info bootstrap. + * + * @param fileModel the file model + * @param onCloseCommand the on close command + * @param mapAllowedMimeTypesForPreview the map allowed mime types for preview + */ + public DialogGetInfoBootstrap(final FileModel fileModel, final Command onCloseCommand, Map> mapAllowedMimeTypesForPreview) { + initWidget(uiBinder.createAndBindUi(this)); + this.fileModel = fileModel; + this.onCloseCommand = onCloseCommand; + this.mapAllowedMimeTypesForPreview = mapAllowedMimeTypesForPreview; + this.cgTxtMimeType.setVisible(true); + + buttonClose.getElement().getStyle().setFloat(Float.RIGHT); + + hpItemType.add(fileModel.getIcon()); + Label labelItemType = new Label(); + labelItemType.setType(LabelType.DEFAULT); + //labelItemType.getElement().getStyle().setMarginLeft(10, Unit.PX); + String label = null; + + GXTFolderItemTypeEnum typeEnum = fileModel.getGXTFolderItemType(); + + //in case of folder see #19600 + if(fileModel.isDirectory()) { + + label = "Private Folder"; + + if(fileModel.isPublic()) { + //is public + label = "Public Folder"; + if(fileModel.isShared()) { + label = "Shared and Public Folder"; + } + }else { + //is not public + if(fileModel.isShared()) { + //is shared + label = "Shared Folder"; + + if(fileModel.isVreFolder()) { + label = "VRE Folder"; + } + } + } + + //hiding the type + cgTxtMimeType.setVisible(false); + + }else { + //in case of file see #19600 + if (typeEnum != null) { + //the file is categorized + label = typeEnum.getLabel(); + label = label.replace("External ", ""); + + } else { + //the file is NOT categorized using the default "File" + label = "File"; + } + } + + + labelItemType.setText(label); + hpItemType.add(labelItemType); + + buttonDownload.setType(ButtonType.LINK); + buttonDownload.setIcon(IconType.CLOUD_DOWNLOAD); + tooltipDownload.add(buttonDownload); + hpItemType.add(tooltipDownload); + +// buttonShareableLink.setType(ButtonType.LINK); +// buttonShareableLink.setIcon(IconType.LINK); +// buttonShareableLink.set +// tooltipSharebleLink.add(buttonShareableLink); +// hpItemType.add(tooltipSharebleLink); + + + // Setting name + htmlSetValue(txtName, fileModel.getName()); + htmlSetValue(txtId, fileModel.getIdentifier()); + + if (fileModel.isRoot()) + txtLocation.setHTML("/"); + else + loadLocation(fileModel); + + if (fileModel.isDirectory()) { + cgTxtIsPublic.setVisible(true); + htmlSetValue(txtIsPublic, fileModel.isPublic() + ""); + + if (fileModel.getSynchedThreddsStatus() != null) { + txtThreddsSynched.setVisible(true); + htmlSetValue(txtThreddsSynched, fileModel.getSynchedThreddsStatus() + ""); + txtThreddsSynched.setHTML(fileModel.getSynchedThreddsStatus() + ""); + } + + } + + //mimetype + htmlSetValue(txtMimeType, fileModel.getType()); + + txtAreaDescription.setResize(ResizeType.VERTICAL); + + if (fileModel.isDirectory()) { + txtAreaDescription.setValue(fileModel.getDescription()); + // add(txtAreaDescription); + } else + loadDescription(fileModel.getIdentifier()); + + //owner + htmlSetValue(txtOwner, fileModel.getOwnerFullName()); + //creation date + loadCreationDate(fileModel.getIdentifier()); + + if(fileModel instanceof FileGridModel) { + FileGridModel fileGridModel = ((FileGridModel) fileModel); + //last update + htmlSetValue(txtLastMofication, dateFormatter.format(fileGridModel.getLastModification())); + //size + fileSize = fileGridModel.getSize(); + htmlSetValue(txtSize, getFormattedSize(fileGridModel.getSize())); + }else { + loadLastModificationDate(fileModel.getIdentifier()); + loadSize(fileModel.getIdentifier()); + + } + + htmlSetValue(txtShared, fileModel.isShared()+""); + + // USERS SHARED + if (fileModel.isShared()) { + + cgSharedWith.setVisible(true); + loadACLsDescriptionForSharedFolder(fileModel.getIdentifier()); + } + + boolean previewManaged = false; + + if (typeEnum != null) { + + // is it an image? + if (typeEnum.equals(GXTFolderItemTypeEnum.IMAGE_DOCUMENT) + || typeEnum.equals(GXTFolderItemTypeEnum.EXTERNAL_IMAGE)) { + previewManaged = true; + loadThumbnailsForImage(); + } + // is it a GCUBE-Item? + if (typeEnum.equals(GXTFolderItemTypeEnum.GCUBE_ITEM)) { + previewManaged = true; //preview not avaible for the type GCUBE_ITEM + loadGcubeItemProperties(); + } + } + + //If the preview is not managed + //through the previous code + //managing it by checking the mime-type + if(!previewManaged) { + + if (!fileModel.isDirectory() && mapAllowedMimeTypesForPreview.containsKey(fileModel.getType())) { + // SOLUTION BASED ON GOOGLE DOC VIEWER + GWT.log("Mime type " + fileModel.getType() + " allowed for preview, try to display it"); + + final HTML loadingPreviewHTML = new HTML(); + setPlaceholder(loadingPreviewHTML, true, "loading preview..."); + htmlPanelFilePreview.add(loadingPreviewHTML); + htmlPanelFilePreview.setVisible(true); + + AppControllerExplorer.rpcWorkspaceService.getPublicLinkForFileItemId(fileModel.getIdentifier(), false, + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + removePlaceHolder(loadingPreviewHTML); + GWT.log("Error on loading the Public link for: "+fileModel.getIdentifier()); + htmlPanelFilePreview.add(noPreviewAvailable); + htmlPanelFilePreview.setVisible(true); + } + + @Override + public void onSuccess(PublicLink result) { + + GWT.log("The PublicLink link is: " + result); + + if (result != null) { + + // if file size is null or greater than 25MB + long byteTo25MB = 1024 * 1024 * 25; + GWT.log("The file size is: " + fileSize); + if (fileSize == null || fileSize > byteTo25MB) { + GWT.log("The file size is null or greater than " + byteTo25MB + ", returning"); + // htmlPanelFilePreview.add(new Image(Resources.getPreviewNotAvailable())); + return; + } + + String googleDocViewerURL = "https://docs.google.com/viewer?url=" + + URL.encode(result.getCompleteURL()) + "&embedded=true"; + + iFrameGDV = instanceFrame(googleDocViewerURL, loadingPreviewHTML); + + final long startTime = new Date().getTime(); + timerGDV = new Timer() { + + @Override + public void run() { + GWT.log("Checking if the iFrameGoogleDocViewer is ready"); + if (iFrameGoogleDocViewerLoaded) { + removePlaceHolder(loadingPreviewHTML); + GWT.log("iFrameGoogleDocViewer currently loaded, cancelling timer"); + cancel(); + return; + } + long checkTime = new Date().getTime(); + long diff = checkTime - startTime; + if (diff > PREVIEW_WAITING_TIME) {// is greater than 10 sec + try { + GWT.log("iFrameGoogleDocViewer not loaded within "+PREVIEW_WAITING_TIME+" sec, cancelling timer, removing iframe"); + cancel(); + removePlaceHolder(loadingPreviewHTML); + htmlPanelFilePreview.add(noPreviewAvailable); + iFrameGDV.setVisible(false); + htmlPanelFilePreview.remove(iFrameGDV); + } catch (Exception e) { + // Silent + } + } + } + }; + timerGDV.scheduleRepeating(PREVIEW_WAITING_TIME/3); + htmlPanelFilePreview.add(iFrameGDV); + + } + } + }); + } else { + GWT.log("Mime type " + fileModel.getType() + " NOT allowed for preview, displaying 'No preview available'"); + htmlPanelFilePreview.add(noPreviewAvailable); + htmlPanelFilePreview.setVisible(true); + } + } + + addHandlers(); + } + + @Override + protected void onDetach() { + super.onDetach(); + GWT.log("Detached..."); + htmlPanelFilePreview.clear(); + if(timerGDV!=null) { + try { + timerGDV.cancel(); + }catch (Exception e) { + // TODO: handle exception + } + } + } + + public Frame instanceFrame(String fileURL, final HTML thePreviewPlaceholder) { + //addLoading(); + String urlEncoded = URL.encode(fileURL); + GWT.log("Encoded url for instanciating frame is " + urlEncoded); + + iFrameGoogleDocViewerLoaded = false; + + final NamedFrame frame = new NamedFrame("iFrameGoogleDocViewer"); + frame.setUrl(urlEncoded); + frame.setVisible(false); + frame.getElement().setId("iFrameGoogleDocViewer"); + frame.getElement().getStyle().setBorderWidth(0, Unit.PX); + frame.addLoadHandler(new LoadHandler() { + + @Override + public void onLoad(LoadEvent arg0) { + GWT.log("iFrameGoogleDocViewer loaded"); + iFrameGoogleDocViewerLoaded = true; + removePlaceHolder(thePreviewPlaceholder); + frame.getElement().addClassName("my-preview-doc"); + frame.setVisible(true); + + } + }); + return frame; + } + + /** + * Adds the handlers. + */ + private void addHandlers() { + + buttonClose.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + onCloseCommand.execute(); + } + }); + + buttonUpdateDescription.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + txtAreaDescription.setReadOnly(false); + txtAreaDescription.setFocus(true); + buttonSaveDescription.setVisible(true); + } + }); + + buttonSaveDescription.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + buttonSaveDescription.setVisible(false); + txtAreaDescription.setReadOnly(true); + + AppControllerExplorer.rpcWorkspaceService.updateDescriptionForItem(fileModel.getIdentifier(), txtAreaDescription.getValue(), new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + new MessageBoxAlert("Error on updating description...", caught.getMessage(), null); + } + + @Override + public void onSuccess(String result) { + GWT.log("Updated the description as: "+result); + txtAreaDescription.setValue(result); + } + }); + } + }); + + final Command cmdReloadProperties = new Command() { + + @Override + public void execute() { + loadGcubeItemProperties(); + } + }; + + buttonUpdateGcubeProperties.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + + final DialogEditProperties editProperties = new DialogEditProperties(fileModel, cmdReloadProperties); + editProperties.show(); + editProperties.setProperties(gCubeProperties); + } + }); + + buttonUpdateShare.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + AppControllerExplorer.getEventBus().fireEvent(new CreateSharedFolderEvent(fileModel, fileModel.getParentFileModel(),false)); + onCloseCommand.execute(); + } + }); + + buttonDownload.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + AppControllerExplorer.getEventBus() + .fireEvent(new FileDownloadEvent(fileModel.getIdentifier(), fileModel.getName(), + DownloadType.SHOW, fileModel.isDirectory() || fileModel.isVreFolder(), null)); + } + }); + } + + /** + * Html set value. + * + * @param field the field + * @param value the value + */ + private void htmlSetValue(HTML field, String value) { + + if (value == null || value.isEmpty()) + field.setHTML(NOT_AVAILABLE); + else + field.setHTML(value); + } + + /** + * Gets the formatted size. + * + * @param value the value + * @return the formatted size + */ + private String getFormattedSize(long value) { + + if (value > 0) { + double kb = value / 1024; + if (kb < 1) + kb = 1; + return number.format(kb); + } else if (value == 0) { + return EMPTY; + } else + return ""; + } + + /** + * Load location. + * + * @param fileModel the file model + */ + private void loadLocation(FileModel fileModel) { + + setPlaceholder(txtLocation, false, "loading..."); + AppControllerExplorer.rpcWorkspaceService.getListParentsByItemIdentifier(fileModel.getIdentifier(), false, + new AsyncCallback>() { + + @Override + public void onFailure(Throwable caught) { + GWT.log("failure get list parents by item identifier " + caught); + removePlaceHolder(txtLocation); + txtLocation.setHTML(NOT_AVAILABLE); + // txtLocation.set(false); + } + + @Override + public void onSuccess(List result) { + removePlaceHolder(txtLocation); + + String location = ""; + if (result != null) { + for (FileModel fileModel : result) { + if (fileModel != null) + location += "/" + fileModel.getName(); + } + } + if (location.isEmpty()) + location = "/"; + + txtLocation.setHTML(location); + } + }); + + } + + /** + * Load size. + * + * @param itemId the item id + */ + private void loadSize(final String itemId) { + GWT.log("Load size"); + setPlaceholder(txtSize, false, "loading..."); + fileSize = new Long(-1); //means is loading + AppControllerExplorer.rpcWorkspaceService.loadSizeByItemId(itemId, new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + fileSize = null; + GWT.log("an error occured in load creation date by Id " + itemId + " " + caught.getMessage()); + removePlaceHolder(txtSize); + + } + + @Override + public void onSuccess(Long result) { + GWT.log("Loaded size=" + result); + fileSize = result; + removePlaceHolder(txtSize); + if(result!=null) + htmlSetValue(txtSize, getFormattedSize(result)); + else + htmlSetValue(txtSize, null); + } + }); + } + + /** + * Load creation date. + * + * @param itemId the item id + */ + private void loadCreationDate(final String itemId) { + + setPlaceholder(txtCreated, false, "loading..."); + AppControllerExplorer.rpcWorkspaceService.getItemCreationDateById(itemId, new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + GWT.log("an error occured in load creation date by Id " + itemId + " " + caught.getMessage()); + removePlaceHolder(txtCreated); + } + + @Override + public void onSuccess(Date dateResult) { + removePlaceHolder(txtCreated); + if (dateResult != null) { + htmlSetValue(txtCreated, dateFormatter.format(dateResult)); + }else + htmlSetValue(txtCreated, null); + + } + }); + } + + /** + * Load last modification date. + * + * @param itemId the item id + */ + private void loadLastModificationDate(final String itemId) { + + setPlaceholder(txtLastMofication, false, "loading..."); + AppControllerExplorer.rpcWorkspaceService.loadLastModificationDateById(itemId, new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + GWT.log("an error occured in loadLastModificationDateById " + itemId + " " + caught.getMessage()); + removePlaceHolder(txtLastMofication); + } + + @Override + public void onSuccess(Date dateResult) { + removePlaceHolder(txtLastMofication); + if (dateResult != null) { + htmlSetValue(txtLastMofication, dateFormatter.format(dateResult)); + }else + htmlSetValue(txtLastMofication, null); + + } + }); + + } + + /** + * Load description. + * + * @param identifier the identifier + */ + private void loadDescription(String identifier) { + txtAreaDescription.setEnabled(false); + + AppControllerExplorer.rpcWorkspaceService.getItemDescriptionById(identifier, new AsyncCallback() { + + @Override + public void onFailure(Throwable arg0) { + txtAreaDescription.setEnabled(false); + + } + + @Override + public void onSuccess(String result) { + if (result != null) + txtAreaDescription.setValue(result); + else + txtAreaDescription.setValue(""); + + txtAreaDescription.setEnabled(true); + + } + }); + + } + + /** + * Load gcube item properties. + */ + private void loadGcubeItemProperties() { + // mask("Loading properties..."); + AppControllerExplorer.rpcWorkspaceService.loadGcubeItemProperties(fileModel.getIdentifier(), + new AsyncCallback>() { + + @Override + public void onSuccess(Map result) { + txtAreaGcubeProperties.setText(""); + GWT.log("Gcube Item Properties: " + result); + gCubeProperties = result; + // unmask(); + if (result != null && result.size() > 0) { + for (String key : result.keySet()) { + String text = txtAreaGcubeProperties.getText(); + text += key + "=" + result.get(key) + ";\n"; + txtAreaGcubeProperties.setText(text); + } + cgGcubeProperties.setVisible(true); + } + } + + @Override + public void onFailure(Throwable caught) { + // unmask(); + cgGcubeProperties.setVisible(false); + GWT.log("an error occured in loadGcubeItemProperties " + fileModel.getIdentifier() + " " + + caught.getMessage()); + } + }); + } + + /** + * Load AC ls description for shared folder. + * + * @param sharedId the shared id + */ + private void loadACLsDescriptionForSharedFolder(String sharedId) { + + setPlaceholder(txtSharedWith, true, "loading..."); + + WorkspaceSharingServiceAsync.INSTANCE.getACLsDescriptionForSharedFolderId(sharedId, + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + removePlaceHolder(txtSharedWith); + txtSharedWith.setHTML("Error on recovering users"); + + } + + @Override + public void onSuccess(String result) { + removePlaceHolder(txtSharedWith); + txtSharedWith.getElement().addClassName("shared-with-style"); + GWT.log("Loaded ACLs: " + result); + txtSharedWith.setHTML(result); + + } + }); + + } + + + /** + * Load thumbnails for image. + */ + private void loadThumbnailsForImage() { + + htmlPanelImagePreview.setVisible(true); + final HTML txtLoadingPreview = new HTML(); + htmlPanelImagePreview.add(txtLoadingPreview); + setPlaceholder(txtLoadingPreview, true, "loading preview..."); + + AppControllerExplorer.rpcWorkspaceService.getImageById(fileModel.getIdentifier(), + fileModel.getGXTFolderItemType().equals(GXTFolderItemTypeEnum.IMAGE_DOCUMENT), false, + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + removePlaceHolder(txtLoadingPreview); + + } + + @Override + public void onSuccess(GWTWorkspaceItem item) { + GWT.log("Image loaded: " + item.getName() + " label: " + item.getLabel() + " type: " + + fileModel.getGXTFolderItemType()); + if (fileModel.getGXTFolderItemType().equals(GXTFolderItemTypeEnum.IMAGE_DOCUMENT)) { + GWTImageDocument theItemImage = (GWTImageDocument) item; + htmlPanelImagePreview.add(new Image(theItemImage.getThumbnailUrl())); + htmlPanelImagePreview.setVisible(true); + }else { + GWTExternalImage theExternalImage = (GWTExternalImage) item; + htmlPanelImagePreview.add(new Image(theExternalImage.getThumbnailUrl())); + htmlPanelImagePreview.setVisible(true); + } + removePlaceHolder(txtLoadingPreview); + } + }); + } + + /** + * Sets the placeholder. + * + * @param html the html + * @param placeholder the placeholder + */ + private void setPlaceholder(HTML html, boolean spinner, String placeholder) { + String loadingHMTL = placeholder; + if(spinner) { + loadingHMTL = ""+placeholder+""; + } + html.setHTML(loadingHMTL); + html.getElement().addClassName("placeholder-loading"); + } + + /** + * Removes the place holder. + * + * @param html the html + */ + private void removePlaceHolder(HTML html) { + html.setHTML(""); + html.getElement().removeClassName("placeholder-loading"); + } + + + public static native String showPDFPreview(String pdfURL, String divId)/*-{ + var theDivContainer = "#"+divId; + $wnd.PDFObject.embed(pdfURL, theDivContainer); + }-*/; + +} diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.ui.xml b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.ui.xml new file mode 100644 index 0000000..4a1a391 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/DialogGetInfoBootstrap.ui.xml @@ -0,0 +1,173 @@ + + + + .no-border { + border: 0px; + } + + + + Details + + + + + + + + + + + + + + + Name + + + + + + + Id + + + + + + + Location + + + + + + + Public + + + + + + + Type + + + + + + + Thredds Sync + + + + + + + Description + + + + + Edit + + + Save + + + + + Gcube Properties + + + + + Edit + + + + + Owner + + + + + + + Created + + + + + + + Modified + + + + + + + Size + + + + + + + Shared + + + + + + + + Shared with + + + + + Share + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/accounting/AccoutingInfoContainer.java b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/accounting/AccoutingInfoContainer.java index 39fe098..a089d53 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/accounting/AccoutingInfoContainer.java +++ b/src/main/java/org/gcube/portlets/user/workspace/client/view/windows/accounting/AccoutingInfoContainer.java @@ -13,7 +13,6 @@ import org.gcube.portlets.widgets.workspacesharingwidget.shared.InfoContactModel import com.extjs.gxt.ui.client.Style.ButtonScale; import com.extjs.gxt.ui.client.Style.HorizontalAlignment; -import com.extjs.gxt.ui.client.data.BaseModel; import com.extjs.gxt.ui.client.data.BaseModelData; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.event.ButtonEvent; diff --git a/src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js b/src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js new file mode 100644 index 0000000..b1e3ec5 --- /dev/null +++ b/src/main/java/org/gcube/portlets/user/workspace/public/js/pdfobject.js @@ -0,0 +1,286 @@ +/*global ActiveXObject, window, console, define, module, jQuery */ +//jshint unused:false, strict: false + +/* + PDFObject v2.1.1 + https://github.com/pipwerks/PDFObject + Copyright (c) 2008-2018 Philip Hutchison + MIT-style license: http://pipwerks.mit-license.org/ + UMD module pattern from https://github.com/umdjs/umd/blob/master/templates/returnExports.js +*/ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else if (typeof module === 'object' && module.exports) { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.PDFObject = factory(); + } +}(this, function () { + + "use strict"; + //jshint unused:true + + //PDFObject is designed for client-side (browsers), not server-side (node) + //Will choke on undefined navigator and window vars when run on server + //Return boolean false and exit function when running server-side + + if(typeof window === "undefined" || typeof navigator === "undefined"){ return false; } + + var pdfobjectversion = "2.1.1", + ua = window.navigator.userAgent, + + //declare booleans + supportsPDFs, + isIE, + supportsPdfMimeType = (typeof navigator.mimeTypes['application/pdf'] !== "undefined"), + supportsPdfActiveX, + isModernBrowser = (function (){ return (typeof window.Promise !== "undefined"); })(), + isFirefox = (function (){ return (ua.indexOf("irefox") !== -1); } )(), + isFirefoxWithPDFJS = (function (){ + //Firefox started shipping PDF.js in Firefox 19. + //If this is Firefox 19 or greater, assume PDF.js is available + if(!isFirefox){ return false; } + //parse userAgent string to get release version ("rv") + //ex: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:57.0) Gecko/20100101 Firefox/57.0 + return (parseInt(ua.split("rv:")[1].split(".")[0], 10) > 18); + })(), + isIOS = (function (){ return (/iphone|ipad|ipod/i.test(ua.toLowerCase())); })(), + + //declare functions + createAXO, + buildFragmentString, + log, + embedError, + embed, + getTargetElement, + generatePDFJSiframe, + generateEmbedElement; + + + /* ---------------------------------------------------- + Supporting functions + ---------------------------------------------------- */ + + createAXO = function (type){ + var ax; + try { + ax = new ActiveXObject(type); + } catch (e) { + ax = null; //ensure ax remains null + } + return ax; + }; + + //IE11 still uses ActiveX for Adobe Reader, but IE 11 doesn't expose + //window.ActiveXObject the same way previous versions of IE did + //window.ActiveXObject will evaluate to false in IE 11, but "ActiveXObject" in window evaluates to true + //so check the first one for older IE, and the second for IE11 + //FWIW, MS Edge (replacing IE11) does not support ActiveX at all, both will evaluate false + //Constructed as a method (not a prop) to avoid unneccesarry overhead -- will only be evaluated if needed + isIE = function (){ return !!(window.ActiveXObject || "ActiveXObject" in window); }; + + //If either ActiveX support for "AcroPDF.PDF" or "PDF.PdfCtrl" are found, return true + //Constructed as a method (not a prop) to avoid unneccesarry overhead -- will only be evaluated if needed + supportsPdfActiveX = function (){ return !!(createAXO("AcroPDF.PDF") || createAXO("PDF.PdfCtrl")); }; + + //Determines whether PDF support is available + supportsPDFs = ( + //as of iOS 12, inline PDF rendering is still not supported in Safari or native webview + //3rd-party browsers (eg Chrome, Firefox) use Apple's webview for rendering, and thus the same result as Safari + //Therefore if iOS, we shall assume that PDF support is not available + !isIOS && ( + //Modern versions of Firefox come bundled with PDFJS + isFirefoxWithPDFJS || + //Browsers that still support the original MIME type check + supportsPdfMimeType || ( + //Pity the poor souls still using IE + isIE() && supportsPdfActiveX() + ) + ) + ); + + //Create a fragment identifier for using PDF Open parameters when embedding PDF + buildFragmentString = function(pdfParams){ + + var string = "", + prop; + + if(pdfParams){ + + for (prop in pdfParams) { + if (pdfParams.hasOwnProperty(prop)) { + string += encodeURIComponent(prop) + "=" + encodeURIComponent(pdfParams[prop]) + "&"; + } + } + + //The string will be empty if no PDF Params found + if(string){ + + string = "#" + string; + + //Remove last ampersand + string = string.slice(0, string.length - 1); + + } + + } + + return string; + + }; + + log = function (msg){ + if(typeof console !== "undefined" && console.log){ + console.log("[PDFObject] " + msg); + } + }; + + embedError = function (msg){ + log(msg); + return false; + }; + + getTargetElement = function (targetSelector){ + + //Default to body for full-browser PDF + var targetNode = document.body; + + //If a targetSelector is specified, check to see whether + //it's passing a selector, jQuery object, or an HTML element + + if(typeof targetSelector === "string"){ + + //Is CSS selector + targetNode = document.querySelector(targetSelector); + + } else if (typeof jQuery !== "undefined" && targetSelector instanceof jQuery && targetSelector.length) { + + //Is jQuery element. Extract HTML node + targetNode = targetSelector.get(0); + + } else if (typeof targetSelector.nodeType !== "undefined" && targetSelector.nodeType === 1){ + + //Is HTML element + targetNode = targetSelector; + + } + + return targetNode; + + }; + + generatePDFJSiframe = function (targetNode, url, pdfOpenFragment, PDFJS_URL, id){ + + var fullURL = PDFJS_URL + "?file=" + encodeURIComponent(url) + pdfOpenFragment; + var scrollfix = (isIOS) ? "-webkit-overflow-scrolling: touch; overflow-y: scroll; " : "overflow: hidden; "; + var iframe = "
"; + targetNode.className += " pdfobject-container"; + targetNode.style.position = "relative"; + targetNode.style.overflow = "auto"; + targetNode.innerHTML = iframe; + return targetNode.getElementsByTagName("iframe")[0]; + + }; + + generateEmbedElement = function (targetNode, targetSelector, url, pdfOpenFragment, width, height, id){ + + var style = ""; + + if(targetSelector && targetSelector !== document.body){ + style = "width: " + width + "; height: " + height + ";"; + } else { + style = "position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%;"; + } + + targetNode.className += " pdfobject-container"; + targetNode.innerHTML = ""; + + return targetNode.getElementsByTagName("embed")[0]; + + }; + + embed = function(url, targetSelector, options){ + + //Ensure URL is available. If not, exit now. + if(typeof url !== "string"){ return embedError("URL is not valid"); } + + //If targetSelector is not defined, convert to boolean + targetSelector = (typeof targetSelector !== "undefined") ? targetSelector : false; + + //Ensure options object is not undefined -- enables easier error checking below + options = (typeof options !== "undefined") ? options : {}; + + //Get passed options, or set reasonable defaults + var id = (options.id && typeof options.id === "string") ? "id='" + options.id + "'" : "", + page = (options.page) ? options.page : false, + pdfOpenParams = (options.pdfOpenParams) ? options.pdfOpenParams : {}, + fallbackLink = (typeof options.fallbackLink !== "undefined") ? options.fallbackLink : true, + width = (options.width) ? options.width : "100%", + height = (options.height) ? options.height : "100%", + assumptionMode = (typeof options.assumptionMode === "boolean") ? options.assumptionMode : true, + forcePDFJS = (typeof options.forcePDFJS === "boolean") ? options.forcePDFJS : false, + PDFJS_URL = (options.PDFJS_URL) ? options.PDFJS_URL : false, + targetNode = getTargetElement(targetSelector), + fallbackHTML = "", + pdfOpenFragment = "", + fallbackHTML_default = "

This browser does not support inline PDFs. Please download the PDF to view it: Download PDF

"; + + //If target element is specified but is not valid, exit without doing anything + if(!targetNode){ return embedError("Target element cannot be determined"); } + + + //page option overrides pdfOpenParams, if found + if(page){ + pdfOpenParams.page = page; + } + + //Stringify optional Adobe params for opening document (as fragment identifier) + pdfOpenFragment = buildFragmentString(pdfOpenParams); + + //Do the dance + + //If the forcePDFJS option is invoked, skip everything else and embed as directed + if(forcePDFJS && PDFJS_URL){ + + return generatePDFJSiframe(targetNode, url, pdfOpenFragment, PDFJS_URL, id); + + //If traditional support is provided, or if this is a modern browser and not iOS (see comment for supportsPDFs declaration) + } else if(supportsPDFs || (assumptionMode && isModernBrowser && !isIOS)){ + + return generateEmbedElement(targetNode, targetSelector, url, pdfOpenFragment, width, height, id); + + //If everything else has failed and a PDFJS fallback is provided, try to use it + } else if(PDFJS_URL){ + + return generatePDFJSiframe(targetNode, url, pdfOpenFragment, PDFJS_URL, id); + + } else { + + //Display the fallback link if available + if(fallbackLink){ + + fallbackHTML = (typeof fallbackLink === "string") ? fallbackLink : fallbackHTML_default; + targetNode.innerHTML = fallbackHTML.replace(/\[url\]/g, url); + + } + + return embedError("This browser does not support embedded PDFs"); + + } + + }; + + return { + embed: function (a,b,c){ return embed(a,b,c); }, + pdfobjectversion: (function () { return pdfobjectversion; })(), + supportsPDFs: (function (){ return supportsPDFs; })() + }; + +})); \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/workspace/public/workspacetree.css b/src/main/java/org/gcube/portlets/user/workspace/public/workspacetree.css index ad9e41b..eb8e29e 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/public/workspacetree.css +++ b/src/main/java/org/gcube/portlets/user/workspace/public/workspacetree.css @@ -273,18 +273,18 @@ table.userssuggest th { top: 2% !important; } -.my-control-group .controls{ +.my-control-group .controls { margin-left: 70px !important; } .my-control-group .control-label { - width: 80px !important; - text-align: center !important; - padding-right: 10px !important; + width: 80px !important; + text-align: center !important; + padding-right: 10px !important; } -.my-control-group .add-on{ - width: 20px !important; +.my-control-group .add-on { + width: 20px !important; } .my-control-group .gwt-TextBox { @@ -300,4 +300,133 @@ table.userssuggest th { cursor: default; color: gray !important; text-decoration: none; +} + +.my-control-group-get-info { + margin-bottom: 5px !important; + margin-left: 15px; + font-size: 14px !important; + font-family: Arial, serif; + color: #222; + +} + +.my-control-group-get-info .controls { + margin-left: 70px !important; +} + +.my-control-group-get-info .control-label { + width: 80px !important; + text-align: left !important; + padding-right: 10px !important; + font-family: Roboto, Arial, serif !important; + color: #959595; +} + +.my-control-group-get-info .add-on { + width: 20px !important; +} + +.my-control-group-get-info .gwt-HTML { + padding-top: 5px; + font-family: Roboto, Arial, serif !important; + word-wrap: break-word; + overflow-wrap: anywhere; + overflow: hidden; +} + +.my-control-group-get-info .gwt-TextBox:hover { + cursor: text !important; +} + +.my-control-group-get-info .gwt-TextArea { + width: 260px; + min-height: 60px; + height: 60px; +} + +.my-control-group-get-info .btn-link { + margin-left: 7px !important; +} + +.item-type-style { + margin-top: 1px; + margin-left: 10px; + margin-bottom: 10px; + padding-top: 5px; + padding-bottom: 5px; +} + +.item-type-style td { + height: 30px; +} + +.item-type-style td:first-child { + width: 30px; + padding-left: 5px; +} + +.item-type-style td { + vertical-align: middle !important; +} + +/*THIS IS THE SIZE OF DOWNLOAD ICON +IN THE 'DETAILS' PANEL*/ +.item-type-style td a i{ + font-size: 22px; +} + + +.item-details-header { + margin-top: 15px; + margin-left: 15px; + margin-right: 15px; +} + +.item-details-header td { + vertical-align: middle !important; +} + +.item-details-header td:last-child { + width: 85%; + color: #555; +} + +.item-details-header .gwt-HTML { + font-size: 20px; + font-family: Roboto, Arial, serif !important; + color: #555; +} + +.placeholder-loading { + color: rgb(142, 142, 142); +} + +.shared-with-style{ + width: 90% !important; + font-size: 12px !important; + display: inline-block !important; +} + +.preview-image-style { + width: 95%; + display: flex; + align-items: center; + justify-content: center; +} + +.preview-image-style img { + max-width: 400px; +} + +.preview-file-style { + width: 95%; + display: flex; + align-items: center; + justify-content: center; +} + +.my-preview-doc { + width: 350px; + height: 350px; } \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/workspace/server/GWTWorkspaceServiceImpl.java b/src/main/java/org/gcube/portlets/user/workspace/server/GWTWorkspaceServiceImpl.java index c4be0d8..d71cd0a 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/server/GWTWorkspaceServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/workspace/server/GWTWorkspaceServiceImpl.java @@ -53,6 +53,7 @@ import org.gcube.portlets.user.workspace.server.reader.ApplicationProfileReader; import org.gcube.portlets.user.workspace.server.tostoragehub.FormatterUtil; import org.gcube.portlets.user.workspace.server.tostoragehub.ObjectStorageHubToWorkpaceMapper; import org.gcube.portlets.user.workspace.server.tostoragehub.StorageHubToWorkpaceConverter; +import org.gcube.portlets.user.workspace.server.util.MimeTypeUtility; import org.gcube.portlets.user.workspace.server.util.PortalContextInfo; import org.gcube.portlets.user.workspace.server.util.StringUtil; import org.gcube.portlets.user.workspace.server.util.WsUtil; @@ -3075,5 +3076,58 @@ public class GWTWorkspaceServiceImpl extends RemoteServiceServlet implements GWT throw new Exception(error); } } + + + /** + * Update description for item. + * + * @param itemId the item id + * @param newDescription the new description + * @return the string + * @throws Exception the exception + */ + @Override + public String updateDescriptionForItem(String itemId, String newDescription) throws Exception { + workspaceLogger.info("Called updateDescriptionForItem for itemID: " + itemId); + + if (itemId == null || itemId.isEmpty()) + throw new Exception("I can't update the description, the itemId is null"); + + workspaceLogger.debug("New description is: " + newDescription); + + try { + + org.gcube.common.storagehubwrapper.server.tohl.Workspace workspace = getWorkspaceFromStorageHub(); + newDescription = workspace.updateDescriptionForItem(itemId, newDescription); + + } catch (Exception e) { + workspaceLogger.error("Error on updating the description for item: " + itemId, e); + String error = ConstantsExplorer.SERVER_ERROR + " updating the description for item with id: " + + "" + itemId+". Error reported: "+e.getMessage(); + throw new Exception(error); + } + + return newDescription; + } + + + + /** + * Gets the allowed mimetypes for preview. + * + * @return the allowed mimetypes for preview + */ + + @Override + public Map> getAllowedMimetypesForPreview(){ + workspaceLogger.info("Called getAllowedMimetypesForPreview"); + + Map> map = MimeTypeUtility.getPreviewMimetypeExtensionMap(); + + workspaceLogger.debug("Returning allowed mimetypes for preview: "+map.keySet()); + + return map; + + } } diff --git a/src/main/java/org/gcube/portlets/user/workspace/server/ImageServlet.java b/src/main/java/org/gcube/portlets/user/workspace/server/ImageServlet.java index fe33f8a..57a4313 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/server/ImageServlet.java +++ b/src/main/java/org/gcube/portlets/user/workspace/server/ImageServlet.java @@ -145,17 +145,21 @@ public class ImageServlet extends HttpServlet{ try{ streamDescr = wa.getThumbnailData(image.getId()); - - /*TODO - * UNCOMMENT THIS IF YOU WANT TO ADD MORE CONTROLS - ReusableInputStream ris = new ReusableInputStream(streamDescr.getStream()); + logger.debug("Thumbnail data has size: "+streamDescr.getSize()); + //CHECKING IF THE STREAM IS A VALID IMAGE + /* TODO + * ReusableInputStream ris = new ReusableInputStream(streamDescr.getStream()); boolean isAvalidImage = isAnImage(ris, image.getName()); - if(!isAvalidImage) + if(!isAvalidImage) { //CREATING THE THUMBNAIL + logger.debug("the stream seems not be a valid image, creating the thumbnail"); streamDescr = createThumbnailForImage(wa, image); - else { + }else { //ASSIGNING THE REUSABLE STREAM - streamDescr = new org.gcube.common.storagehubwrapper.shared.tohl.impl.StreamDescriptor(ris, image.getName(), null, image.getMimeType()); + logger.debug("using reusable stream"); + size = streamDescr.getSize()==null?0:streamDescr.getSize(); + logger.debug("ReusableInputStream has size: "+size); + streamDescr = new org.gcube.common.storagehubwrapper.shared.tohl.impl.StreamDescriptor(ris, image.getName(), size, streamDescr.getMimeType()); }*/ @@ -186,8 +190,9 @@ public class ImageServlet extends HttpServlet{ resp.setContentType(mimeType); //if image/thumbnail size is 0, skipping setContentLength - if(size!=0) - resp.setContentLength((int)size); + //AVOIDING TO SET IT, SOME CASES THE SIZE MISMATCH +// if(size!=0) +// resp.setContentLength((int)size); InputStream in = streamDescr.getStream(); diff --git a/src/main/java/org/gcube/portlets/user/workspace/server/util/MimeTypeUtility.java b/src/main/java/org/gcube/portlets/user/workspace/server/util/MimeTypeUtility.java index 454d9f7..1d94814 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/server/util/MimeTypeUtility.java +++ b/src/main/java/org/gcube/portlets/user/workspace/server/util/MimeTypeUtility.java @@ -17,11 +17,10 @@ import org.apache.commons.io.FilenameUtils; import org.apache.tika.config.TikaConfig; import org.apache.tika.detect.Detector; import org.apache.tika.io.TikaInputStream; -import org.apache.tika.metadata.Metadata; -import org.apache.tika.mime.MediaType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +// TODO: Auto-generated Javadoc /** * The Class MimeTypeUtil. * @@ -48,15 +47,19 @@ public class MimeTypeUtility { protected static final Map> mimetype_extension_map = new LinkedHashMap>(); protected static final Map extension_mimetype_map = new LinkedHashMap(); + protected static final Map> preview_mimetype_extension_map = new LinkedHashMap>(); static { InputStream extensionToMimetype = MimeTypeUtility.class .getResourceAsStream("/WsExtensionToMimeTypeMap.properties"); InputStream mimetypeToExtension = MimeTypeUtility.class .getResourceAsStream("/WsMimeTypeToExtensionMap.properties"); + InputStream previewMimeTypeToExtension = MimeTypeUtility.class + .getResourceAsStream("/PreviewMimeTypeToExtensionMap.properties"); try { loadExtensions(extensionToMimetype); loadMimeTypes(mimetypeToExtension); + loadPreviewMimeTypes(previewMimeTypeToExtension); } catch (IOException e) { e.printStackTrace(); } @@ -114,6 +117,35 @@ public class MimeTypeUtility { } br.close(); } + + + /** + * Load preview mime types. + * + * @param is the is + * @throws IOException Signals that an I/O exception has occurred. + */ + protected static void loadPreviewMimeTypes(InputStream is) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + String line = br.readLine(); + + while (line != null) { + String[] split = line.split("="); + if (split.length == 2) { + String mimeType = split[0]; + String extension = split[1]; + List toExtensions = preview_mimetype_extension_map.get(mimeType); + if (toExtensions == null) { + toExtensions = new ArrayList(); + } + toExtensions.add(extension); + preview_mimetype_extension_map.put(mimeType, toExtensions); + } + line = br.readLine(); + } + br.close(); + } /** * Gets the extension. @@ -279,5 +311,16 @@ public class MimeTypeUtility { public static Map getExtensionToMimeTypeMap() { return extension_mimetype_map; } + + + /** + * Gets the preview mimetype extension map with the + * mime types allowed for preview displaying + * + * @return the preview mimetype extension map + */ + public static Map> getPreviewMimetypeExtensionMap() { + return preview_mimetype_extension_map; + } } diff --git a/src/main/java/org/gcube/portlets/user/workspace/server/util/ThumbnailGenerator.java b/src/main/java/org/gcube/portlets/user/workspace/server/util/ThumbnailGenerator.java index af11c18..b6e7932 100644 --- a/src/main/java/org/gcube/portlets/user/workspace/server/util/ThumbnailGenerator.java +++ b/src/main/java/org/gcube/portlets/user/workspace/server/util/ThumbnailGenerator.java @@ -136,7 +136,7 @@ public class ThumbnailGenerator { extension = extension.startsWith(".") ? extension : "." + extension; final File tempFile = File.createTempFile(filename, extension); - //tempFile.deleteOnExit(); + tempFile.deleteOnExit(); try (FileOutputStream out = new FileOutputStream(tempFile)) { IOUtils.copy(in, out); } diff --git a/src/main/resources/PreviewMimeTypeToExtensionMap.properties b/src/main/resources/PreviewMimeTypeToExtensionMap.properties new file mode 100644 index 0000000..4f280e0 --- /dev/null +++ b/src/main/resources/PreviewMimeTypeToExtensionMap.properties @@ -0,0 +1,62 @@ +application/msword=doc +application/pdf=pdf +application/rtf=rtf +application/vnd.ms-excel=xls +application/vnd.ms-powerpoint=ppt +application/vnd.openxmlformats-officedocument.wordprocessingml.document=docx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet=xlsx +application/vnd.openxmlformats-officedocument.presentationml.presentation=pptx +application/x-javascript=js +application/json=json +audio/mid=mid +audio/mpeg=mp3 +audio/x-wav=wav +image/bmp=bmp +image/gif=gif +image/ief=ief +image/jpeg=jpe +image/jpeg=jpeg +image/jpeg=jpg +image/pipeg=jfif +image/svg+xml=svg +image/tiff=tif +image/tiff=tiff +image/x-cmu-raster=ras +image/x-cmx=cmx +image/x-icon=ico +image/x-rgb=rgb +text/css=css +text/html=htm +text/html=stm +text/html=html +text/plain=bas +text/plain=c +text/plain=h +text/plain=txt +text/richtext=rtx +text/scriptlet=sct +text/tab-separated-values=tsv +text/uri-list=txt +text/webviewhtml=htt +text/x-component=htc +video/mpeg=mp2 +video/mpeg=mpa +video/mpeg=mpe +video/mpeg=mpeg +video/mpeg=mpg +video/mpeg=mpv2 +video/quicktime=mov +video/quicktime=qt +video/x-la-asf=lsf +video/x-la-asf=lsx +video/x-ms-asf=asf +video/x-ms-asf=asr +video/x-ms-asf=asx +video/x-msvideo=avi +video/x-sgi-movie=movie +x-world/x-vrml=flr +x-world/x-vrml=vrml +x-world/x-vrml=wrl +x-world/x-vrml=wrz +x-world/x-vrml=xaf +x-world/x-vrml=xof \ No newline at end of file