diff --git a/logicaldoc-core/src/main/java/com/logicaldoc/core/folder/HibernateFolderDAO.java b/logicaldoc-core/src/main/java/com/logicaldoc/core/folder/HibernateFolderDAO.java index aebe7d185..b5346bac4 100644 --- a/logicaldoc-core/src/main/java/com/logicaldoc/core/folder/HibernateFolderDAO.java +++ b/logicaldoc-core/src/main/java/com/logicaldoc/core/folder/HibernateFolderDAO.java @@ -122,10 +122,20 @@ public void store(Folder folder) throws PersistenceException { public void store(Folder folder, FolderHistory transaction) throws PersistenceException { if (!checkStoringAspect()) return; - + if (folder.getId() != 0L && getCurrentSession().contains(folder)) getCurrentSession().merge(folder); + if (folder.getType() == Folder.TYPE_WORKSPACE) { + Folder defaultWs = findDefaultWorkspace(folder.getTenantId()); + if (defaultWs != null && defaultWs.equals(folder) && !folder.getName().equals(Folder.DEFAULTWORKSPACENAME)) + throw new PersistenceException("You cannot rename the default workspace"); + + Folder root = findRoot(folder.getTenantId()); + if (root != null && folder.getParentId() != root.getId()) + throw new PersistenceException("You cannot move a workspace"); + } + if (!folder.getName().equals(SLASH)) { // To avoid java script and xml injection folder.setName(HTMLSanitizer.sanitizeSimpleText(folder.getName())); @@ -157,7 +167,7 @@ public void store(Folder folder, FolderHistory transaction) throws PersistenceEx folder.getAttributes().values().removeIf(Attribute::isSection); AccessControlUtil.removeForbiddenPermissionsForGuests(folder); - + if (folder.getTemplate() == null) { folder.setOcrTemplateId(null); folder.setBarcodeTemplateId(null); @@ -167,7 +177,7 @@ public void store(Folder folder, FolderHistory transaction) throws PersistenceEx Map dictionary = new HashMap<>(); for (FolderListener listener : listenerManager.getListeners()) listener.beforeStore(folder, transaction, dictionary); - + saveOrUpdate(folder); if (StringUtils.isEmpty(folder.getPath())) { folder.setPath(computePath(folder.getId())); @@ -1159,7 +1169,7 @@ private void checkIfCanDelete(long folderId) throws PersistenceException { if (folderId == rootId) throw new PersistenceException("You cannot delete folder " + folder.getName() + " - " + folderId); - if (folder.getName().equals("Default") && folder.getParentId() == rootId) + if (folder.getName().equals(Folder.DEFAULTWORKSPACENAME) && folder.getParentId() == rootId) throw new PersistenceException("You cannot delete folder " + folder.getName() + " - " + folderId); } @@ -2213,7 +2223,7 @@ public void applyStoreToTree(long id, FolderHistory transaction) throws Persiste @Override public void applyOCRToTree(long id, FolderHistory transaction) throws PersistenceException { Folder parent = getExistingFolder(id); - + transaction.setEvent(FolderEvent.CHANGED.toString()); transaction.setTenantId(parent.getTenantId()); transaction.setNotifyEvent(false); diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/data/FoldersDS.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/data/FoldersDS.java index fb6130b54..27022f3d2 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/data/FoldersDS.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/data/FoldersDS.java @@ -45,6 +45,9 @@ public FoldersDS(String id, boolean nopagination, Long max) { DataSourceTextField folderId = new DataSourceTextField("folderId", I18N.message("id")); folderId.setHidden(true); + + DataSourceTextField parentId = new DataSourceTextField("parentId", I18N.message("parentid")); + parentId.setHidden(true); DataSourceTextField foldRef = new DataSourceTextField("foldRef"); foldRef.setHidden(true); @@ -59,7 +62,7 @@ public FoldersDS(String id, boolean nopagination, Long max) { parent.setForeignKey(dsId + ".id"); parent.setRootValue("/"); - setFields(recordId, name, folderId, foldRef, parent, type, size, color); + setFields(recordId, name, folderId, parentId, foldRef, parent, type, size, color); setDataURL( "data/folders.xml" + (nopagination ? "?nopagination=true" : "") + (max != null ? "&max=" + max : "")); diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebSocketListener.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebSocketListener.java index d4f38d1a4..f120d6cb7 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebSocketListener.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebSocketListener.java @@ -116,6 +116,10 @@ public WebsocketMessage deserializeMessage(String data) { } private void onEvent(WebsocketMessage event) { + // Skip events related to other tenants + if (event.getTenantId() != Session.get().getInfo().getTenant().getId()) + return; + if (!moniteredEvents.contains(event.getEvent())) return; @@ -149,19 +153,18 @@ private void handleEvent(WebsocketMessage event) { } else if ("event.reading.requested".equals(event.getEvent())) { String recipient = event.getComment().substring(event.getComment().indexOf(':') + 1).trim(); if (Session.get().getUser().getUsername().equals(recipient)) { - ReadingRequestService.Instance.get() - .getUnconfimedReadings(new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(List readings) { - ReadingRequestController.get().addUnconfirmedReadings(readings); - } - }); + ReadingRequestService.Instance.get().getUnconfimedReadings(new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(List readings) { + ReadingRequestController.get().addUnconfirmedReadings(readings); + } + }); } } else if (isCommandEvent(event)) { processCommand(event); diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebsocketMessage.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebsocketMessage.java index 1221a7d08..5edb79904 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebsocketMessage.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/common/client/websockets/WebsocketMessage.java @@ -46,6 +46,8 @@ public class WebsocketMessage implements Serializable { private String payload; private String target; + + private long tenantId; public WebsocketMessage(String sid, String event) { super(); @@ -175,4 +177,12 @@ public String getCommand() { public void setCommand(String command) { this.command = command; } + + public long getTenantId() { + return tenantId; + } + + public void setTenantId(long tenantId) { + this.tenantId = tenantId; + } } \ No newline at end of file diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/ContextMenu.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/ContextMenu.java index 61713a818..247c2dcd0 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/ContextMenu.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/ContextMenu.java @@ -199,7 +199,9 @@ protected void fillContextMenu(GUIFolder folder, final List selecti workflow.addClickHandler(click -> new StartWorkflowDialog(getSelectionIds(selection)).show()); automation = new MenuItem(I18N.message("executeautomation")); - automation.addClickHandler(click -> new AutomationDialog(folder.getId(), getSelectionIds(selection)).show()); + automation.addClickHandler( + click -> new AutomationDialog(Arrays.asList(new Long[] { folder.getId() }), getSelectionIds(selection)) + .show()); preview = preparePreview(); @@ -1192,8 +1194,8 @@ public void onSuccess(GUIAutomationRoutine routine) { * A routine with parameters is referenced, so * open the input popup */ - FillRoutineParams dialog = new FillRoutineParams(action.getName(), routine, folderId, - selectedDocIds); + FillRoutineParams dialog = new FillRoutineParams(action.getName(), routine, + Arrays.asList(new Long[] { folderId }), selectedDocIds); dialog.show(); } else { /* @@ -1254,18 +1256,19 @@ private void onDownload(final GUIFolder folder, final List selectio } private void executeRoutine(long folderId, List docIds, GUIAutomationRoutine routine) { - AutomationService.Instance.get().execute(routine, docIds, folderId, new AsyncCallback<>() { + AutomationService.Instance.get().execute(routine, docIds, Arrays.asList(new Long[] { folderId }), + new AsyncCallback<>() { - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } - @Override - public void onSuccess(Void arg0) { - // Nothing to do - } - }); + @Override + public void onSuccess(Void arg0) { + // Nothing to do + } + }); } private void onRename(long docId, String newFilename) { diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/FillRoutineParams.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/FillRoutineParams.java index e8bb159df..fc856b428 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/FillRoutineParams.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/document/grid/FillRoutineParams.java @@ -24,17 +24,7 @@ public class FillRoutineParams extends Window { private ExtendedPropertiesPanel propertiesPanel; - private GUIAutomationRoutine routine; - - private long folderId; - - private List docIds; - - public FillRoutineParams(String title, GUIAutomationRoutine routine, long folderId, List docIds) { - this.routine = routine; - this.folderId = folderId; - this.docIds = docIds; - + public FillRoutineParams(String title, GUIAutomationRoutine routine, List folderIds, List docIds) { setHeaderControls(HeaderControls.HEADER_LABEL, HeaderControls.CLOSE_BUTTON); setTitle(title); setWidth(500); @@ -47,7 +37,7 @@ public FillRoutineParams(String title, GUIAutomationRoutine routine, long folder IButton execute = new IButton(); execute.setTitle(I18N.message("execute")); execute.setAutoFit(true); - execute.addClickHandler(event -> onExecute()); + execute.addClickHandler(event -> onExecute(routine, docIds, folderIds)); HLayout buttonsBar = new HLayout(); buttonsBar.setWidth100(); @@ -64,11 +54,11 @@ public FillRoutineParams(String title, GUIAutomationRoutine routine, long folder addItem(layout); } - public void onExecute() { + public void onExecute(GUIAutomationRoutine routine, List folderIds, List docIds) { if (!propertiesPanel.validate()) return; - AutomationService.Instance.get().execute(routine, docIds, folderId, new AsyncCallback<>() { + AutomationService.Instance.get().execute(routine, docIds, folderIds, new AsyncCallback<>() { @Override public void onFailure(Throwable caught) { diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/AutomationDialog.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/AutomationDialog.java index 68babe7fe..0f01a729c 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/AutomationDialog.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/AutomationDialog.java @@ -44,7 +44,7 @@ public class AutomationDialog extends Window { private TabSet tabSet = new TabSet(); - public AutomationDialog(Long folderId, List docIds) { + public AutomationDialog(List folderIds, List docIds) { HeaderControl closeIcon = new HeaderControl(HeaderControl.CLOSE, (ClickEvent event) -> destroy()); setHeaderControls(HeaderControls.HEADER_LABEL, closeIcon); @@ -59,7 +59,7 @@ public AutomationDialog(Long folderId, List docIds) { ToolStripButton execute = new ToolStripButton(); execute.setTitle(I18N.message("execute")); - execute.addClickHandler(event -> onExecute(folderId, docIds)); + execute.addClickHandler(event -> onExecute(folderIds, docIds)); ToolStripButton close = new ToolStripButton(); close.setTitle(I18N.message("close")); @@ -136,7 +136,7 @@ private Tab prepareParametersTab() { return new Tab(I18N.message("parameters")); } - private void onExecute(Long folderId, List docIds) { + private void onExecute(List folderIds, List docIds) { if (routine.getId() == 0L && !scriptForm.validate()) return; @@ -149,7 +149,7 @@ private void onExecute(Long folderId, List docIds) { LD.contactingServer(); AutomationDialog.this.destroy(); GuiLog.info(I18N.message("automationlaunched")); - AutomationService.Instance.get().execute(routine, docIds, folderId, new AsyncCallback<>() { + AutomationService.Instance.get().execute(routine, docIds, folderIds, new AsyncCallback<>() { @Override public void onFailure(Throwable caught) { diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/ContextMenu.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/ContextMenu.java new file mode 100644 index 000000000..f9ea4011a --- /dev/null +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/ContextMenu.java @@ -0,0 +1,599 @@ +package com.logicaldoc.gui.frontend.client.folder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.google.gwt.http.client.RequestTimeoutException; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.logicaldoc.gui.common.client.Constants; +import com.logicaldoc.gui.common.client.Feature; +import com.logicaldoc.gui.common.client.Session; +import com.logicaldoc.gui.common.client.beans.GUIAccessControlEntry; +import com.logicaldoc.gui.common.client.beans.GUIAutomationRoutine; +import com.logicaldoc.gui.common.client.beans.GUIFolder; +import com.logicaldoc.gui.common.client.beans.GUIMenu; +import com.logicaldoc.gui.common.client.controllers.FolderController; +import com.logicaldoc.gui.common.client.i18n.I18N; +import com.logicaldoc.gui.common.client.log.GuiLog; +import com.logicaldoc.gui.common.client.services.SecurityService; +import com.logicaldoc.gui.common.client.util.ItemFactory; +import com.logicaldoc.gui.common.client.util.LD; +import com.logicaldoc.gui.common.client.util.Util; +import com.logicaldoc.gui.common.client.util.ValuesCallback; +import com.logicaldoc.gui.frontend.client.clipboard.Clipboard; +import com.logicaldoc.gui.frontend.client.document.DocumentsPanel; +import com.logicaldoc.gui.frontend.client.document.SendToArchiveDialog; +import com.logicaldoc.gui.frontend.client.document.grid.FillRoutineParams; +import com.logicaldoc.gui.frontend.client.folder.copy.FolderCopyDialog; +import com.logicaldoc.gui.frontend.client.panels.MainPanel; +import com.logicaldoc.gui.frontend.client.search.Search; +import com.logicaldoc.gui.frontend.client.services.AutomationService; +import com.logicaldoc.gui.frontend.client.services.DocumentService; +import com.logicaldoc.gui.frontend.client.services.FolderService; +import com.logicaldoc.gui.frontend.client.subscription.SubscriptionDialog; +import com.smartgwt.client.util.SC; +import com.smartgwt.client.widgets.form.fields.CheckboxItem; +import com.smartgwt.client.widgets.form.fields.FormItem; +import com.smartgwt.client.widgets.menu.Menu; +import com.smartgwt.client.widgets.menu.MenuItem; +import com.smartgwt.client.widgets.tree.TreeNode; + +/** + * This context menu is used for trees containing folders + * + * @author Marco Meschieri - LogicalDOC + * @since 8.9.4 + */ +public class ContextMenu extends Menu { + + private FolderNavigator tree; + + private GUIAccessControlEntry acl; + + private List selectedFolders; + + public ContextMenu(FolderNavigator tree, GUIAccessControlEntry acl) { + this.tree = tree; + this.acl = acl; + this.selectedFolders = tree.getSelectedFolders(); + + GUIFolder firstSelectedFolder = selectedFolders.get(0); + + MenuItem search = prepareSearchMenuItem(firstSelectedFolder); + + MenuItem delete = prepareDeleteMenuItem(); + + MenuItem create = prepareCreateMenuItem(firstSelectedFolder); + + MenuItem createAlias = prepareCreateAliasMenuItem(); + + MenuItem rename = prepareRenameMenuItem(firstSelectedFolder); + + MenuItem createWorkspace = new MenuItem(); + createWorkspace.setTitle(I18N.message("newworkspace")); + createWorkspace.addClickHandler(click -> onCreateWorkspace()); + + MenuItem reload = new MenuItem(); + reload.setTitle(I18N.message("reload")); + reload.addClickHandler(click -> tree.reload()); + + MenuItem move = prepareMoveMenuItem(); + + MenuItem copy = prepareCopyMenuItem(); + + MenuItem merge = prepareMergeMenuItem(); + + MenuItem paste = new MenuItem(); + paste.setTitle(I18N.message("paste")); + paste.addClickHandler(click -> onPaste(firstSelectedFolder)); + + MenuItem pasteAsAlias = new MenuItem(); + pasteAsAlias.setTitle(I18N.message("pasteasalias")); + pasteAsAlias.addClickHandler(click -> onPasteAsAlias(firstSelectedFolder)); + + MenuItem exportZip = prepareExportZipMenuItem(firstSelectedFolder); + + MenuItem addBookmark = new MenuItem(); + addBookmark.setTitle(I18N.message("addbookmark")); + addBookmark.addClickHandler(click -> onAddBookmark(tree.getSelectedIds())); + + if (!acl.isWrite() || Clipboard.getInstance().isEmpty()) { + paste.setEnabled(false); + pasteAsAlias.setEnabled(false); + } + + pasteAsAlias.setEnabled(!Clipboard.getInstance().getLastAction().equals(Clipboard.CUT)); + + if (Session.get().getUser().isMemberOf(Constants.GROUP_ADMIN) && Feature.visible(Feature.MULTI_WORKSPACE)) { + setItems(reload, search, create, createAlias, rename, createWorkspace, delete, addBookmark, paste, + pasteAsAlias, move, copy, merge, exportZip); + } else { + setItems(reload, search, create, createAlias, rename, delete, addBookmark, paste, pasteAsAlias, move, copy, + merge, exportZip); + } + + addSubscribeMenuItem(); + + addApplyTemplateMenuItem(); + + addArchiveMenuItem(); + + addSendToExportArchiveMenuItem(); + + addAutomationMenuItem(); + + addCustomActionsMenuItem(); + + if (selectedFolders.size() == 1) + FolderService.Instance.get().getFolder(firstSelectedFolder.getId(), false, false, false, + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(GUIFolder selectedFolder) { + delete.setEnabled(!selectedFolder.isDefaultWorkspace()); + move.setEnabled(false); + merge.setEnabled(false); + rename.setEnabled(!selectedFolder.isDefaultWorkspace()); + createWorkspace.setEnabled(Feature.enabled(Feature.MULTI_WORKSPACE)); + } + }); + } + + private void addCustomActionsMenuItem() { + if (Feature.enabled(Feature.CUSTOM_ACTIONS) + && com.logicaldoc.gui.common.client.Menu.enabled(com.logicaldoc.gui.common.client.Menu.CUSTOM_ACTIONS) + && !Session.get().getUser().getCustomActions().isEmpty()) { + MenuItem customActionsItem = prepareCustomActionsMenu(); + addItem(customActionsItem); + } + } + + private MenuItem prepareCustomActionsMenu() { + Menu customActionsMenu = new Menu(); + for (GUIMenu menuAction : Session.get().getUser().getCustomActions()) + prepareCustomActionMenuItem(menuAction, customActionsMenu); + + MenuItem customActionsItem = new MenuItem(I18N.message("customactions")); + customActionsItem.setSubmenu(customActionsMenu); + return customActionsItem; + } + + private void prepareCustomActionMenuItem(GUIMenu menuAction, Menu customActionsMenu) { + MenuItem actionItem = new MenuItem(I18N.message(menuAction.getName())); + customActionsMenu.addItem(actionItem); + + actionItem.addClickHandler(event -> + /** + * Check on the server if the action has been modified + */ + SecurityService.Instance.get().getMenu(menuAction.getId(), I18N.getLocale(), new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(GUIMenu action) { + Session.get().getUser().updateCustomAction(action); + + if ((action.getRoutineId() == null || action.getRoutineId().longValue() == 0L) + && action.getAutomation() != null && !action.getAutomation().trim().isEmpty()) { + /* + * An automation cript is specified directly, so launch it's + * execution + */ + GUIAutomationRoutine routine = new GUIAutomationRoutine(); + routine.setAutomation(action.getAutomation()); + executeRoutine(tree.getSelectedIds(), null, routine); + } else if (action.getRoutineId() != null && action.getRoutineId().longValue() != 0L) { + AutomationService.Instance.get().getRoutine(action.getRoutineId(), new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(GUIAutomationRoutine routine) { + if (routine.getTemplateId() != null && routine.getTemplateId().longValue() != 0L) { + /* + * A routine with parameters is referenced, so + * open the input popup + */ + new FillRoutineParams(action.getName(), routine, tree.getSelectedIds(), null).show(); + } else { + /* + * A routine without parameters is referenced, + * so launch directly + */ + executeRoutine(tree.getSelectedIds(), null, routine); + } + } + }); + } + } + })); + } + + private void executeRoutine(List folderIds, List docIds, GUIAutomationRoutine routine) { + AutomationService.Instance.get().execute(routine, docIds, folderIds, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void arg0) { + // Nothing to do + } + }); + } + + private void addAutomationMenuItem() { + if (Feature.visible(Feature.AUTOMATION)) { + MenuItem automation = new MenuItem(); + automation.setTitle(I18N.message("executeautomation")); + automation.addClickHandler(eaClick -> new AutomationDialog(tree.getSelectedIds(), null).show()); + addItem(automation); + automation.setEnabled(Feature.enabled(Feature.AUTOMATION) && acl.isAutomation()); + } + } + + private void addSendToExportArchiveMenuItem() { + if (Feature.visible(Feature.IMPEX)) { + MenuItem sendToExpArchive = new MenuItem(); + sendToExpArchive.setTitle(I18N.message("sendtoexparchive")); + sendToExpArchive.addClickHandler( + event -> LD.ask(I18N.message("question"), I18N.message("confirmputinexparchive"), yes -> { + if (Boolean.TRUE.equals(yes)) { + new SendToArchiveDialog(tree.getSelectedIds(), false).show(); + } + })); + addItem(sendToExpArchive); + sendToExpArchive.setEnabled(Feature.enabled(Feature.IMPEX) && acl.isExport()); + } + } + + private void addArchiveMenuItem() { + if (Feature.visible(Feature.ARCHIVING) && selectedFolders.size() == 1) { + MenuItem archive = new MenuItem(); + archive.setTitle(I18N.message("archive")); + archive.addClickHandler(archiveClick -> onArchive(selectedFolders.get(0).getId())); + addItem(archive); + archive.setEnabled(Feature.enabled(Feature.ARCHIVING) && acl.isArchive()); + } + } + + private void addApplyTemplateMenuItem() { + if (Feature.visible(Feature.FOLDER_TEMPLATE) && selectedFolders.size() == 1) { + MenuItem applyTemplate = new MenuItem(); + applyTemplate.setTitle(I18N.message("applytemplate")); + applyTemplate.addClickHandler(applyTemplateClick -> new ApplyTemplateDialog().show()); + addItem(applyTemplate); + applyTemplate.setEnabled(Feature.enabled(Feature.FOLDER_TEMPLATE) && acl.isAdd()); + } + } + + private void addSubscribeMenuItem() { + if (Feature.visible(Feature.AUDIT) && selectedFolders.size() == 1) { + MenuItem subscribe = new MenuItem(); + subscribe.setTitle(I18N.message("subscribe")); + subscribe.addClickHandler(click -> new SubscriptionDialog(selectedFolders.get(0).getId(), null).show()); + subscribe.setEnabled(Feature.enabled(Feature.AUDIT)); + addItem(subscribe); + } + } + + private MenuItem prepareCopyMenuItem() { + MenuItem copy = new MenuItem(); + copy.setTitle(I18N.message("copy")); + copy.addClickHandler(copyClick -> new FolderCopyDialog().show()); + return copy; + } + + private MenuItem prepareCreateAliasMenuItem() { + MenuItem createAlias = new MenuItem(); + createAlias.setTitle(I18N.message("createalias")); + createAlias.addClickHandler(caClick -> new CreateAliasDialog().show()); + createAlias.setEnabled( + acl.isAdd() && tree.getSelectedRecord().getAttributeAsString(FolderNavigator.FOLD_REF) == null); + return createAlias; + } + + private MenuItem prepareExportZipMenuItem(final GUIFolder folder) { + MenuItem exportZip = new MenuItem(); + exportZip.setTitle(I18N.message("exportzip")); + exportZip.addClickHandler( + event -> Window.open(Util.contextPath() + "zip-export?folderId=" + folder.getId(), "_blank", "")); + exportZip.setEnabled(acl.isExport() && acl.isDownload()); + return exportZip; + } + + private MenuItem prepareMoveMenuItem() { + MenuItem move = new MenuItem(); + move.setTitle(I18N.message("move")); + move.addClickHandler(event -> new MoveDialog().show()); + move.setEnabled(acl.isMove()); + return move; + } + + private MenuItem prepareMergeMenuItem() { + MenuItem merge = new MenuItem(); + merge.setTitle(I18N.message("merge")); + merge.addClickHandler(event -> new MergeDialog().show()); + merge.setEnabled(acl.isDelete()); + return merge; + } + + private MenuItem prepareDeleteMenuItem() { + MenuItem delete = new MenuItem(); + delete.setTitle(I18N.message("ddelete")); + delete.addClickHandler(event -> onDelete()); + delete.setEnabled(acl.isDelete()); + return delete; + } + + private MenuItem prepareSearchMenuItem(GUIFolder folder) { + MenuItem search = new MenuItem(); + search.setTitle(I18N.message("search")); + search.addClickHandler(click -> { + Search.get().getOptions().setFolder(folder.getId()); + Search.get().getOptions().setFolderName(folder.getName()); + Search.get().getOptions().setSearchInSubPath(false); + Search.get().setOptions(Search.get().getOptions()); + MainPanel.get().selectSearchTab(); + }); + return search; + } + + private MenuItem prepareRenameMenuItem(final GUIFolder folder) { + MenuItem rename = new MenuItem(); + rename.setTitle(I18N.message("rename")); + rename.addClickHandler(event -> onRename()); + rename.setEnabled(acl.isRename()); + return rename; + } + + private MenuItem prepareCreateMenuItem(final GUIFolder folder) { + MenuItem create = new MenuItem(); + create.setTitle(I18N.message("newfolder")); + + GUIFolder newFolder=new GUIFolder(); + newFolder.setParentId(folder.getId()); + create.addClickHandler(event -> new CreateDialog(newFolder).show()); + create.setEnabled(acl.isAdd()); + return create; + } + + private void onDelete() { + final List selectedIds = tree.getSelectedIds(); + LD.contactingServer(); + DocumentService.Instance.get().countDocuments(selectedIds, Constants.DOC_ARCHIVED, new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + LD.clearPrompt(); + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Long count) { + LD.clearPrompt(); + final String folderMessage = selectedIds.size() == 1 ? "confirmdeletefolder" : "confirmdeletefolders"; + final String documentMessage = selectedIds.size() == 1 ? "confirmdeletefolderarchdocs" + : "confirmdeletefoldersarchdocs"; + LD.ask(I18N.message("question"), + count.longValue() == 0L ? (I18N.message(folderMessage)) : (I18N.message(documentMessage)), + yes -> { + if (Boolean.TRUE.equals(yes)) { + LD.contactingServer(); + doDelete(selectedIds); + } + }); + } + }); + } + + private void doDelete(final List selectedIds) { + TreeNode parentNode = tree.getTree().getParent(tree.getSelectedRecord()); + TreeNode firstNode = tree.getTree().getChildren(parentNode)[0]; + + FolderService.Instance.get().delete(selectedIds, new AsyncCallback<>() { + @Override + public void onFailure(Throwable caught) { + LD.clearPrompt(); + + if (caught instanceof RequestTimeoutException) + SC.say("timeout"); + + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void result) { + LD.clearPrompt(); + + for (long id : selectedIds) { + TreeNode node = tree.getTree().find( + com.logicaldoc.gui.frontend.client.folder.browser.FolderTree.FOLDER_ID, Long.toString(id)); + if (node != null) + tree.getTree().remove(node); + } + + if (parentNode == null || "/".equals(tree.getTree().getPath(parentNode))) { + // In case of a workspace we close the whole tree and select + // first workspace + tree.getTree().closeAll(); + tree.selectFolder(Long.parseLong(firstNode.getAttributeAsString( + com.logicaldoc.gui.frontend.client.folder.browser.FolderTree.FOLDER_ID))); + tree.getTree().openFolder(firstNode); + selectRecord(0); + } else { + tree.selectFolder(Long.parseLong(parentNode.getAttributeAsString( + com.logicaldoc.gui.frontend.client.folder.browser.FolderTree.FOLDER_ID))); + tree.reloadParentsOfSelection(); + } + } + }); + } + + private void onRename() { + final TreeNode selectedNode = tree.getSelectedRecord(); + LD.askForValue(I18N.message("rename"), I18N.message("name"), selectedNode.getAttributeAsString("name"), + value -> { + if (value == null || "".equals(value.trim())) + return; + final String val = value.trim().replace("/", "").replace("\\\\", ""); + final long folderId = Long.parseLong(selectedNode.getAttributeAsString( + com.logicaldoc.gui.frontend.client.folder.browser.FolderTree.FOLDER_ID)); + FolderService.Instance.get().rename(folderId, val, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void v) { + selectedNode.setAttribute("name", val); + tree.refreshRow(getRecordIndex(selectedNode)); + } + }); + }); + } + + private void onCreateWorkspace() { + GUIFolder folder = new GUIFolder(); + folder.setType(1); + new CreateDialog(folder).show(); + } + + private void onPaste(GUIFolder folder) { + final long folderId = folder.getId(); + + List items = new ArrayList<>(); + CheckboxItem copyDocuments = ItemFactory.newCheckbox("copydocuments"); + copyDocuments.setValue(true); + copyDocuments.setDisabled(true); + items.add(copyDocuments); + + CheckboxItem copyLinks = ItemFactory.newCheckbox("copylinks"); + copyLinks.setValue(true); + items.add(copyLinks); + + CheckboxItem copyNotes = ItemFactory.newCheckbox("copynotes"); + copyNotes.setValue(true); + items.add(copyNotes); + + CheckboxItem copySecuerity = ItemFactory.newCheckbox("copysecurity"); + copySecuerity.setValue(true); + items.add(copySecuerity); + + LD.askForValues(I18N.message("copyoptions"), null, items, null, new ValuesCallback() { + + @Override + public void execute(Map values) { + FolderService.Instance.get().paste( + Clipboard.getInstance().stream().map(doc -> doc.getId()).collect(Collectors.toList()), folderId, + Clipboard.getInstance().getLastAction(), Boolean.TRUE.equals(values.get("copylinks")), + Boolean.TRUE.equals(values.get("copynotes")), Boolean.TRUE.equals(values.get("copysecurity")), + new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void result) { + DocumentsPanel.get().onFolderSelected(FolderController.get().getCurrentFolder()); + Clipboard.getInstance().clear(); + } + }); + } + + @Override + public void execute(String value) { + // Not used + } + }); + } + + private void onPasteAsAlias(GUIFolder folder) { + final long folderId = folder.getId(); + final List docIds = Clipboard.getInstance().stream().map(d -> d.getId()).collect(Collectors.toList()); + + if (Feature.enabled(Feature.PDF)) + LD.askForValue(I18N.message("pasteasalias"), "type", "", ItemFactory.newAliasTypeSelector(), + type -> pasteAsAlias(folderId, docIds, type)); + else + pasteAsAlias(folderId, docIds, null); + } + + private void pasteAsAlias(final long folderId, final List docIds, String type) { + FolderService.Instance.get().pasteAsAlias(docIds, folderId, type, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void result) { + DocumentsPanel.get().onFolderSelected(FolderController.get().getCurrentFolder()); + Clipboard.getInstance().clear(); + GuiLog.debug("Paste as Alias operation completed."); + } + }); + } + + /** + * Adds a bookmark to the currently selected folders + */ + private void onAddBookmark(List selection) { + DocumentService.Instance.get().addBookmarks(selection, 1, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void v) { + // Nothing to do + } + }); + } + + private void onArchive(final long folderId) { + LD.askForValue(I18N.message("warning"), I18N.message("archiveadvice"), "", 400, value -> { + if (value == null) + return; + + if (value.isEmpty()) + SC.warn(I18N.message("commentrequired")); + else + DocumentService.Instance.get().archiveFolder(folderId, value, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Long result) { + GuiLog.info(I18N.message("documentswerearchived", "" + result), null); + tree.reload(); + } + }); + }); + } +} \ No newline at end of file diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateAliasDialog.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateAliasDialog.java index 64a845971..36c0e3d7c 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateAliasDialog.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateAliasDialog.java @@ -1,13 +1,18 @@ package com.logicaldoc.gui.frontend.client.folder; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.logicaldoc.gui.common.client.beans.GUIFolder; import com.logicaldoc.gui.common.client.i18n.I18N; +import com.logicaldoc.gui.common.client.log.GuiLog; import com.logicaldoc.gui.common.client.widgets.FolderTree; +import com.logicaldoc.gui.frontend.client.services.FolderService; import com.smartgwt.client.types.HeaderControls; import com.smartgwt.client.widgets.Button; import com.smartgwt.client.widgets.Dialog; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; import com.smartgwt.client.widgets.tree.TreeGrid; +import com.smartgwt.client.widgets.tree.TreeNode; /** * This is the form used to copy a folder into another path @@ -46,8 +51,7 @@ public CreateAliasDialog() { create.setAutoFit(true); create.setMargin(1); create.addClickHandler(event -> { - FolderNavigator.get() - .createAlias(Long.parseLong(folders.getSelectedRecord().getAttributeAsString("folderId"))); + createAlias(folders.getSelectedRecord().getAttributeAsLong("folderId")); destroy(); }); @@ -55,4 +59,27 @@ public CreateAliasDialog() { content.setMembers(folders, buttons); addItem(content); } + + /** + * Creates an alias in the currently selected folder + * + * @param referencedFolderId The original folder to reference + */ + public void createAlias(long referencedFolderId) { + final TreeNode parent = FolderNavigator.get().getSelectedRecord(); + FolderService.Instance.get().createAlias(parent.getAttributeAsLong(FolderNavigator.FOLDER_ID), + referencedFolderId, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(GUIFolder ret) { + if (parent != null) + FolderNavigator.get().getTree().reloadChildren(parent); + } + }); + } } \ No newline at end of file diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateDialog.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateDialog.java index e1aed05f1..3d3e2813e 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateDialog.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/CreateDialog.java @@ -3,6 +3,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.logicaldoc.gui.common.client.Session; import com.logicaldoc.gui.common.client.beans.GUIFolder; +import com.logicaldoc.gui.common.client.controllers.FolderController; import com.logicaldoc.gui.common.client.i18n.I18N; import com.logicaldoc.gui.common.client.log.GuiLog; import com.logicaldoc.gui.common.client.util.ItemFactory; @@ -14,7 +15,6 @@ import com.smartgwt.client.widgets.form.fields.SubmitItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.layout.VLayout; -import com.smartgwt.client.widgets.tree.TreeNode; /** * This is the form used to create a new Folder @@ -91,27 +91,7 @@ public void onFailure(Throwable caught) { @Override public void onSuccess(GUIFolder newFolder) { - TreeNode newNode = new TreeNode(newFolder.getName()); - newNode.setAttribute("name", newFolder.getName()); - newNode.setAttribute("folderId", Long.toString(newFolder.getId())); - newNode.setAttribute("type", Long.toString(newFolder.getType())); - - if (newFolder.getType() == 1) { - newNode.setAttribute("id", - FolderNavigator.get().getRootNode().getAttributeAsString("id") + "-" - + Long.toString(newFolder.getId())); - FolderNavigator.get().getTree().add(newNode, FolderNavigator.get().getTree().getRoot()); - } else { - TreeNode selectedNode = FolderNavigator.get().getSelectedRecord(); - - newNode.setAttribute("id", selectedNode.getAttributeAsString("id") + "-" - + Long.toString(newFolder.getId())); - - if (Boolean.FALSE.equals(FolderNavigator.get().getTree().isOpen(selectedNode))) - FolderNavigator.get().getTree().openFolder(selectedNode); - FolderNavigator.get().getTree().add(newNode, selectedNode); - } - + FolderController.get().created(newFolder); destroy(); } }); diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/FolderNavigator.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/FolderNavigator.java index 5e16b9465..56ee84e18 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/FolderNavigator.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/FolderNavigator.java @@ -1,60 +1,35 @@ package com.logicaldoc.gui.frontend.client.folder; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; -import com.google.gwt.http.client.RequestTimeoutException; -import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.logicaldoc.gui.common.client.Constants; -import com.logicaldoc.gui.common.client.Feature; import com.logicaldoc.gui.common.client.Session; import com.logicaldoc.gui.common.client.beans.GUIAccessControlEntry; -import com.logicaldoc.gui.common.client.beans.GUIAutomationRoutine; import com.logicaldoc.gui.common.client.beans.GUIDocument; import com.logicaldoc.gui.common.client.beans.GUIFolder; -import com.logicaldoc.gui.common.client.beans.GUIMenu; import com.logicaldoc.gui.common.client.controllers.FolderController; import com.logicaldoc.gui.common.client.controllers.FolderObserver; import com.logicaldoc.gui.common.client.data.FoldersDS; import com.logicaldoc.gui.common.client.i18n.I18N; import com.logicaldoc.gui.common.client.log.GuiLog; -import com.logicaldoc.gui.common.client.services.SecurityService; -import com.logicaldoc.gui.common.client.util.ItemFactory; import com.logicaldoc.gui.common.client.util.LD; import com.logicaldoc.gui.common.client.util.RequestInfo; -import com.logicaldoc.gui.common.client.util.Util; -import com.logicaldoc.gui.common.client.util.ValuesCallback; import com.logicaldoc.gui.common.client.util.WindowUtils; import com.logicaldoc.gui.common.client.widgets.grid.FolderListGridField; -import com.logicaldoc.gui.frontend.client.clipboard.Clipboard; import com.logicaldoc.gui.frontend.client.document.DocumentsPanel; -import com.logicaldoc.gui.frontend.client.document.SendToArchiveDialog; import com.logicaldoc.gui.frontend.client.document.grid.DocumentsGrid; -import com.logicaldoc.gui.frontend.client.document.grid.FillRoutineParams; import com.logicaldoc.gui.frontend.client.folder.browser.FolderCursor; import com.logicaldoc.gui.frontend.client.folder.browser.FolderTree; -import com.logicaldoc.gui.frontend.client.folder.copy.FolderCopyDialog; -import com.logicaldoc.gui.frontend.client.panels.MainPanel; -import com.logicaldoc.gui.frontend.client.search.Search; -import com.logicaldoc.gui.frontend.client.services.AutomationService; import com.logicaldoc.gui.frontend.client.services.DocumentService; import com.logicaldoc.gui.frontend.client.services.FolderService; -import com.logicaldoc.gui.frontend.client.subscription.SubscriptionDialog; import com.smartgwt.client.util.EventHandler; import com.smartgwt.client.util.SC; -import com.smartgwt.client.widgets.form.fields.CheckboxItem; -import com.smartgwt.client.widgets.form.fields.FormItem; import com.smartgwt.client.widgets.grid.ListGridField; import com.smartgwt.client.widgets.grid.ListGridRecord; import com.smartgwt.client.widgets.grid.events.DataArrivedEvent; -import com.smartgwt.client.widgets.menu.Menu; -import com.smartgwt.client.widgets.menu.MenuItem; -import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent; import com.smartgwt.client.widgets.tree.TreeNode; /** @@ -69,7 +44,7 @@ public class FolderNavigator extends FolderTree implements FolderObserver { private static final String COLOR = "color"; - private static final String FOLD_REF = "foldRef"; + static final String FOLD_REF = "foldRef"; private static final String OPERATIONNOTALLOWED = "operationnotallowed"; @@ -197,27 +172,8 @@ private void addDropHandler() { */ private void addCellContextHandler() { addCellContextClickHandler(contextClickEvent -> { - if (getSelectedRecord() != null && getSelectedRecords().length > 1) { - Menu contextMenu = prepateContextMenu(); - contextMenu.showContextMenu(); - } else { - FolderService.Instance.get().getFolder(getSelectedRecord().getAttributeAsLong(FOLDER_ID), false, true, - false, new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(GUIFolder folder) { - Menu contextMenu = prepateContextMenu(folder); - contextMenu.showContextMenu(); - } - }); - } - if (contextClickEvent != null) - contextClickEvent.cancel(); + showContextMenu(); + contextClickEvent.cancel(); }); } @@ -309,374 +265,23 @@ public void onSuccess(GUIFolder result) { } /** - * Prepares the context menu for multiple selection + * Shows the context menu * * @return the prepared context menu */ - private Menu prepateContextMenu() { - MenuItem move = new MenuItem(); - move.setTitle(I18N.message("move")); - move.addClickHandler(event -> { - MoveDialog dialog = new MoveDialog(); - dialog.show(); - }); - - MenuItem copy = new MenuItem(); - copy.setTitle(I18N.message("copy")); - copy.addClickHandler(event -> new FolderCopyDialog().show()); - - MenuItem merge = new MenuItem(); - merge.setTitle(I18N.message("merge")); - merge.addClickHandler(event -> new MergeDialog().show()); - - MenuItem delete = new MenuItem(); - delete.setTitle(I18N.message("ddelete")); - delete.addClickHandler(event -> onDelete()); - - Menu contextMenu = new Menu(); - contextMenu.setItems(move, copy, merge, delete); - - return contextMenu; - } - - /** - * Prepares the context menu for single selection - * - * @param selectedFolder the folder to use - */ - private Menu prepateContextMenu(final GUIFolder selectedFolder) { - - Menu contextMenu = new Menu(); - - MenuItem search = prepareSearchMenuItem(selectedFolder); - - MenuItem delete = prepareDeleteMenuItem(selectedFolder); - - MenuItem create = prepareCreateMenuItem(selectedFolder); - - MenuItem createAlias = prepareCreateAliasMenuItem(); - - MenuItem rename = prepareRenameMenuItem(selectedFolder); - - MenuItem createWorkspace = new MenuItem(); - createWorkspace.setTitle(I18N.message("newworkspace")); - createWorkspace.addClickHandler(click -> onCreateWorkspace()); - - MenuItem reload = new MenuItem(); - reload.setTitle(I18N.message("reload")); - reload.addClickHandler(click -> reload()); - - MenuItem move = prepareMoveMenuItem(selectedFolder); - - MenuItem copy = prepareCopyMenuItem(); - - MenuItem merge = prepareMergeMenuItem(selectedFolder); - - MenuItem paste = new MenuItem(); - paste.setTitle(I18N.message("paste")); - paste.addClickHandler(click -> onPaste()); - - MenuItem pasteAsAlias = new MenuItem(); - pasteAsAlias.setTitle(I18N.message("pasteasalias")); - pasteAsAlias.addClickHandler(click -> onPasteAsAlias()); - - MenuItem exportZip = prepareExportZipMenuItem(selectedFolder); - - MenuItem addBookmark = new MenuItem(); - addBookmark.setTitle(I18N.message("addbookmark")); - addBookmark.addClickHandler(click -> onAddBookmark()); - - if (!selectedFolder.hasPermission(GUIAccessControlEntry.PERMISSION_WRITE) - || Clipboard.getInstance().isEmpty()) { - paste.setEnabled(false); - pasteAsAlias.setEnabled(false); - } - - if (!selectedFolder.hasPermission(GUIAccessControlEntry.PERMISSION_ADD)) { - createAlias.setEnabled(false); - } - - if (Clipboard.getInstance().getLastAction().equals(Clipboard.CUT)) - pasteAsAlias.setEnabled(false); - - if (Session.get().getUser().isMemberOf(Constants.GROUP_ADMIN) && selectedFolder.isWorkspace() - && Feature.visible(Feature.MULTI_WORKSPACE)) { - delete.setEnabled(!selectedFolder.isDefaultWorkspace()); - move.setEnabled(false); - merge.setEnabled(false); - rename.setEnabled(!selectedFolder.isDefaultWorkspace()); - createWorkspace.setEnabled(Feature.enabled(Feature.MULTI_WORKSPACE)); - contextMenu.setItems(reload, search, create, createAlias, rename, createWorkspace, delete, addBookmark, - paste, pasteAsAlias, move, copy, merge, exportZip); - } else { - contextMenu.setItems(reload, search, create, createAlias, rename, delete, addBookmark, paste, pasteAsAlias, - move, copy, merge, exportZip); - } - - addSubscribeMenuItem(selectedFolder, contextMenu); - - addApplyTemplateMenuItem(selectedFolder, contextMenu); - - addArchiveMenuItem(selectedFolder, contextMenu); - - addSendToExportArchiveMenuItem(selectedFolder, contextMenu); - - addAutomationMenuItem(selectedFolder, contextMenu); - - addCustomActionsMenuItem(selectedFolder, contextMenu); - - return contextMenu; - } - - private void addCustomActionsMenuItem(final GUIFolder selectedFolder, Menu contextMenu) { - if (Feature.enabled(Feature.CUSTOM_ACTIONS) - && com.logicaldoc.gui.common.client.Menu.enabled(com.logicaldoc.gui.common.client.Menu.CUSTOM_ACTIONS) - && !Session.get().getUser().getCustomActions().isEmpty()) { - MenuItem customActionsItem = prepareCustomActionsMenu(selectedFolder.getId()); - contextMenu.addItem(customActionsItem); - } - } - - private void addAutomationMenuItem(final GUIFolder selectedFolder, Menu contextMenu) { - if (Feature.visible(Feature.AUTOMATION)) { - MenuItem automation = new MenuItem(); - automation.setTitle(I18N.message("executeautomation")); - automation.addClickHandler(eaClick -> onAutomation(selectedFolder.getId())); - - contextMenu.addItem(automation); - if (!Feature.enabled(Feature.AUTOMATION) - || !selectedFolder.hasPermission(GUIAccessControlEntry.PERMISSION_AUTOMATION)) { - automation.setEnabled(false); - } - } - } - - private void addSendToExportArchiveMenuItem(final GUIFolder folder, Menu contextMenu) { - if (Feature.visible(Feature.IMPEX)) { - MenuItem sendToExpArchive = new MenuItem(); - sendToExpArchive.setTitle(I18N.message("sendtoexparchive")); - sendToExpArchive.addClickHandler( - event -> LD.ask(I18N.message("question"), I18N.message("confirmputinexparchive"), yes -> { - if (Boolean.TRUE.equals(yes)) { - new SendToArchiveDialog(Arrays.asList(folder.getId()), false).show(); - } - })); - contextMenu.addItem(sendToExpArchive); - if (!Feature.enabled(Feature.IMPEX) || !folder.hasPermission(GUIAccessControlEntry.PERMISSION_EXPORT)) - sendToExpArchive.setEnabled(false); - } - } - - private void addArchiveMenuItem(final GUIFolder folder, Menu contextMenu) { - if (Feature.visible(Feature.ARCHIVING)) { - MenuItem archive = new MenuItem(); - archive.setTitle(I18N.message("archive")); - archive.addClickHandler(archiveClick -> onArchive(folder.getId())); - contextMenu.addItem(archive); - if (!Feature.enabled(Feature.ARCHIVING) || !folder.hasPermission(GUIAccessControlEntry.PERMISSION_ARCHIVE)) - archive.setEnabled(false); - } - } - - private void addApplyTemplateMenuItem(final GUIFolder folder, Menu contextMenu) { - if (Feature.visible(Feature.FOLDER_TEMPLATE)) { - MenuItem applyTemplate = new MenuItem(); - applyTemplate.setTitle(I18N.message("applytemplate")); - applyTemplate.addClickHandler(applyTemplateClick -> onApplyTemplate()); - contextMenu.addItem(applyTemplate); - if (!Feature.enabled(Feature.FOLDER_TEMPLATE) - || !folder.hasPermission(GUIAccessControlEntry.PERMISSION_ADD)) - applyTemplate.setEnabled(false); - } - } - - private void addSubscribeMenuItem(GUIFolder folder, Menu contextMenu) { - if (Feature.visible(Feature.AUDIT)) { - MenuItem subscribe = new MenuItem(); - subscribe.setTitle(I18N.message("subscribe")); - subscribe.addClickHandler(click -> new SubscriptionDialog(folder.getId(), null).show()); - subscribe.setEnabled(Feature.enabled(Feature.AUDIT)); - contextMenu.addItem(subscribe); - } - } - - private MenuItem prepareCopyMenuItem() { - MenuItem copy = new MenuItem(); - copy.setTitle(I18N.message("copy")); - copy.addClickHandler(copyClick -> new FolderCopyDialog().show()); - return copy; - } - - private MenuItem prepareCreateAliasMenuItem() { - MenuItem createAlias = new MenuItem(); - createAlias.setTitle(I18N.message("createalias")); - createAlias.addClickHandler(caClick -> new CreateAliasDialog().show()); - createAlias.setEnabled(getSelectedRecord().getAttributeAsString(FOLD_REF) == null); - return createAlias; - } - - private MenuItem prepareExportZipMenuItem(final GUIFolder folder) { - MenuItem exportZip = new MenuItem(); - exportZip.setTitle(I18N.message("exportzip")); - exportZip.addClickHandler( - event -> Window.open(Util.contextPath() + "zip-export?folderId=" + folder.getId(), "_blank", "")); - exportZip.setEnabled(folder.hasPermission(GUIAccessControlEntry.PERMISSION_EXPORT) - && folder.hasPermission(GUIAccessControlEntry.PERMISSION_DOWNLOAD)); - return exportZip; - } - - private MenuItem prepareMoveMenuItem(final GUIFolder folder) { - MenuItem move = new MenuItem(); - move.setTitle(I18N.message("move")); - move.addClickHandler(event -> new MoveDialog().show()); - move.setEnabled(folder.hasPermission(GUIAccessControlEntry.PERMISSION_MOVE) && !folder.isDefaultWorkspace() - && GUIFolder.TYPE_ALIAS != getSelectedRecord().getAttributeAsInt("type")); - return move; - } - - private MenuItem prepareMergeMenuItem(final GUIFolder folder) { - MenuItem merge = new MenuItem(); - merge.setTitle(I18N.message("merge")); - merge.addClickHandler(event -> new MergeDialog().show()); - merge.setEnabled(folder.hasPermission(GUIAccessControlEntry.PERMISSION_DELETE) && !folder.isDefaultWorkspace() - && GUIFolder.TYPE_ALIAS != getSelectedRecord().getAttributeAsInt("type")); - return merge; - } - - private MenuItem prepareDeleteMenuItem(final GUIFolder folder) { - MenuItem delete = new MenuItem(); - delete.setTitle(I18N.message("ddelete")); - delete.addClickHandler(event -> onDelete()); - delete.setEnabled( - folder.hasPermission(GUIAccessControlEntry.PERMISSION_DELETE) && !folder.isDefaultWorkspace()); - return delete; - } - - private MenuItem prepareSearchMenuItem(GUIFolder folder) { - MenuItem search = new MenuItem(); - search.setTitle(I18N.message("search")); - search.addClickHandler((MenuItemClickEvent event) -> { - Search.get().getOptions().setFolder(folder.getId()); - Search.get().getOptions().setFolderName(folder.getName()); - Search.get().getOptions().setSearchInSubPath(false); - Search.get().setOptions(Search.get().getOptions()); - MainPanel.get().selectSearchTab(); - }); - return search; - } - - private MenuItem prepareRenameMenuItem(final GUIFolder folder) { - MenuItem rename = new MenuItem(); - rename.setTitle(I18N.message("rename")); - rename.addClickHandler(event -> onRename()); - rename.setEnabled( - folder.hasPermission(GUIAccessControlEntry.PERMISSION_RENAME) && !folder.isDefaultWorkspace()); - return rename; - } - - private MenuItem prepareCreateMenuItem(final GUIFolder folder) { - MenuItem create = new MenuItem(); - create.setTitle(I18N.message("newfolder")); - create.addClickHandler(event -> onCreate(folder.getId())); - create.setEnabled(folder.hasPermission(GUIAccessControlEntry.PERMISSION_ADD)); - return create; - } - - private void onDelete() { - final List selectedIds = getSelectedIds(); - LD.contactingServer(); - DocumentService.Instance.get().countDocuments(selectedIds, Constants.DOC_ARCHIVED, new AsyncCallback() { - - @Override - public void onFailure(Throwable caught) { - LD.clearPrompt(); - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Long count) { - LD.clearPrompt(); - final String folderMessage = selectedIds.size() == 1 ? "confirmdeletefolder" : "confirmdeletefolders"; - final String documentMessage = selectedIds.size() == 1 ? "confirmdeletefolderarchdocs" - : "confirmdeletefoldersarchdocs"; - LD.ask(I18N.message("question"), - count.longValue() == 0L ? (I18N.message(folderMessage)) : (I18N.message(documentMessage)), - yes -> { - if (Boolean.TRUE.equals(yes)) { - LD.contactingServer(); - doDelete(selectedIds); - } - }); - } - }); - } - - private void doDelete(final List selectedIds) { - TreeNode parentNode = getTree().getParent(getSelectedRecord()); - TreeNode firstNode = getTree().getChildren(parentNode)[0]; - - FolderService.Instance.get().delete(selectedIds, new AsyncCallback<>() { - @Override - public void onFailure(Throwable caught) { - LD.clearPrompt(); - - if (caught instanceof RequestTimeoutException) - SC.say("timeout"); - - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void result) { - LD.clearPrompt(); - - for (long id : selectedIds) { - TreeNode node = getTree().find(FOLDER_ID, Long.toString(id)); - if (node != null) - getTree().remove(node); - } - - if (parentNode == null || "/".equals(getTree().getPath(parentNode))) { - // In case of a workspace we close the whole tree and select - // first workspace - getTree().closeAll(); - selectFolder(Long.parseLong(firstNode.getAttributeAsString(FOLDER_ID))); - getTree().openFolder(firstNode); - selectRecord(0); - } else { - selectFolder(Long.parseLong(parentNode.getAttributeAsString(FOLDER_ID))); - reloadParentsOfSelection(); - } - } - }); - } - - /** - * Allows the selection of a folders template to apply to the current node - */ - private void onApplyTemplate() { - new ApplyTemplateDialog().show(); - } - - /** - * Adds a bookmark to the currently selected folder. - */ - private void onAddBookmark() { - final TreeNode selectedNode = getSelectedRecord(); - final long folderId = Long.parseLong(selectedNode.getAttributeAsString(FOLDER_ID)); - - DocumentService.Instance.get().addBookmarks(Arrays.asList(folderId), 1, new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } + private void showContextMenu() { + FolderService.Instance.get().getAllowedPermissions(getSelectedIds(), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } - @Override - public void onSuccess(Void v) { - // Nothing to do - } - }); + @Override + public void onSuccess(GUIAccessControlEntry acl) { + new ContextMenu(FolderNavigator.this, acl).showContextMenu(); + } + }); } public static FolderNavigator get() { @@ -880,30 +485,6 @@ void onCreate(long parentId) { dialog.show(); } - private void onRename() { - final TreeNode selectedNode = getSelectedRecord(); - LD.askForValue(I18N.message("rename"), I18N.message("name"), selectedNode.getAttributeAsString("name"), - value -> { - if (value == null || "".equals(value.trim())) - return; - final String val = value.trim().replace("/", "").replace("\\\\", ""); - final long folderId = Long.parseLong(selectedNode.getAttributeAsString(FOLDER_ID)); - FolderService.Instance.get().rename(folderId, val, new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void v) { - selectedNode.setAttribute("name", val); - refreshRow(getRecordIndex(selectedNode)); - } - }); - }); - } - void onCreateWorkspace() { GUIFolder folder = new GUIFolder(); folder.setType(1); @@ -911,106 +492,12 @@ void onCreateWorkspace() { dialog.show(); } - private void onPaste() { - TreeNode selectedNode = getSelectedRecord(); - final long folderId = Long.parseLong(selectedNode.getAttribute(FOLDER_ID)); - - List items = new ArrayList<>(); - CheckboxItem copyDocuments = ItemFactory.newCheckbox("copydocuments"); - copyDocuments.setValue(true); - copyDocuments.setDisabled(true); - items.add(copyDocuments); - - CheckboxItem copyLinks = ItemFactory.newCheckbox("copylinks"); - copyLinks.setValue(true); - items.add(copyLinks); - - CheckboxItem copyNotes = ItemFactory.newCheckbox("copynotes"); - copyNotes.setValue(true); - items.add(copyNotes); - - CheckboxItem copySecuerity = ItemFactory.newCheckbox("copysecurity"); - copySecuerity.setValue(true); - items.add(copySecuerity); - - LD.askForValues(I18N.message("copyoptions"), null, items, null, new ValuesCallback() { - - @Override - public void execute(Map values) { - FolderService.Instance.get().paste( - Clipboard.getInstance().stream().map(doc -> doc.getId()).collect(Collectors.toList()), folderId, - Clipboard.getInstance().getLastAction(), Boolean.TRUE.equals(values.get("copylinks")), - Boolean.TRUE.equals(values.get("copynotes")), Boolean.TRUE.equals(values.get("copysecurity")), - new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void result) { - DocumentsPanel.get().onFolderSelected(FolderController.get().getCurrentFolder()); - Clipboard.getInstance().clear(); - } - }); - } - - @Override - public void execute(String value) { - // Not used - } - }); - } - - private void onPasteAsAlias() { - TreeNode selectedNode = getSelectedRecord(); - final long folderId = Long.parseLong(selectedNode.getAttribute(FOLDER_ID)); - final List docIds = Clipboard.getInstance().stream().map(d -> d.getId()).collect(Collectors.toList()); - - if (Feature.enabled(Feature.PDF)) - LD.askForValue(I18N.message("pasteasalias"), "type", "", ItemFactory.newAliasTypeSelector(), - type -> pasteAsAlias(folderId, docIds, type)); - else - pasteAsAlias(folderId, docIds, null); - } - - private void pasteAsAlias(final long folderId, final List docIds, String type) { - FolderService.Instance.get().pasteAsAlias(docIds, folderId, type, new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void result) { - DocumentsPanel.get().onFolderSelected(FolderController.get().getCurrentFolder()); - Clipboard.getInstance().clear(); - GuiLog.debug("Paste as Alias operation completed."); - } - }); - } - @Override public void enable() { super.enable(); getTree().setReportCollisions(false); } - /** - * Gets all the IDs of the selected folders - * - * @return identifiers of folders - */ - public List getSelectedIds() { - ListGridRecord[] selection = getSelectedRecords(); - List ids = new ArrayList<>(); - for (ListGridRecord rec : selection) - ids.add(rec.getAttributeAsLong(FOLDER_ID)); - return ids; - } - /** * Moves the currently selected folder to the new parent folder * @@ -1043,91 +530,6 @@ public void onSuccess(Void ret) { }); } - /** - * Merges the currently selected folders to a target folder - * - * @param targetFolderId The target folder - */ - public void mergeTo(final long targetFolderId) { - List ids = getSelectedIds(); - for (Long id : ids) { - TreeNode node = getTree().find(FOLDER_ID, (Object) id); - getTree().remove(node); - } - - LD.contactingServer(); - FolderService.Instance.get().merge(ids, targetFolderId, new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - LD.clearPrompt(); - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void ret) { - LD.clearPrompt(); - TreeNode target = getTree().find(FOLDER_ID, Long.toString(targetFolderId)); - if (target != null) - getTree().reloadChildren(target); - } - }); - } - - /** - * Copies the currently selected folders to the new parent folder - * - * @param targetFolderId identifier of the parent folder - * @param foldersOnly to create just the folders - * @param securityOption how to setup the security for the new folder'none', - * 'inherit' or 'replicate' - */ - public void copyTo(long targetFolderId, boolean foldersOnly, String securityOption) { - final TreeNode target = getTree().findById(Long.toString(targetFolderId)); - - LD.contactingServer(); - FolderService.Instance.get().copyFolders(getSelectedIds(), targetFolderId, foldersOnly, securityOption, null, - new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - LD.clearPrompt(); - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void ret) { - LD.clearPrompt(); - if (target != null) - getTree().reloadChildren(target); - } - }); - } - - /** - * Creates an alias in the currently selected folder - * - * @param referencedFolderId The original folder to reference - */ - public void createAlias(long referencedFolderId) { - final TreeNode parent = getSelectedRecord(); - - FolderService.Instance.get().createAlias(parent.getAttributeAsLong(FOLDER_ID), referencedFolderId, - new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(GUIFolder ret) { - if (parent != null) - getTree().reloadChildren(parent); - } - }); - } - public boolean isFirstTime() { return firstTime; } @@ -1174,6 +576,9 @@ public void onFolderSelected(GUIFolder folder) { @Override public void onFolderCreated(GUIFolder folder) { TreeNode parent = getTree().find(FOLDER_ID, (Object) folder.getParentId()); + if (parent == null && folder.getType() == GUIFolder.TYPE_WORKSPACE) + parent = getTree().getRoot(); + if (parent == null) return; @@ -1182,6 +587,7 @@ public void onFolderCreated(GUIFolder folder) { node.setName(folder.getName()); node.setAttribute(COLOR, folder.getColor()); node.setAttribute(FOLDER_ID, folder.getId()); + node.setAttribute(PARENT_ID, folder.getParentId()); node.setAttribute("id", parent.getAttribute("id") + "-" + folder.getId()); node.setAttribute("type", folder.getType()); node.setAttribute("customIcon", "folder"); @@ -1247,10 +653,6 @@ public void onSuccess(Long result) { }); } - private void onAutomation(final long folderId) { - new AutomationDialog(folderId, null).show(); - } - public TreeNode getNode(long folderId) { return getTree().find(FOLDER_ID, Long.toString(folderId)); } @@ -1264,7 +666,7 @@ public TreeNode getRootNode() { return getTree().getRoot(); } - private void reloadParentsOfSelection() { + void reloadParentsOfSelection() { ListGridRecord[] selection = getSelectedRecords(); for (ListGridRecord rec : selection) { try { @@ -1286,91 +688,6 @@ public void destroy() { FolderController.get().removeObserver(this); } - private MenuItem prepareCustomActionsMenu(final long folderId) { - Menu customActionsMenu = new Menu(); - for (GUIMenu menuAction : Session.get().getUser().getCustomActions()) - prepareCustomActionMenuItem(folderId, menuAction, customActionsMenu); - - MenuItem customActionsItem = new MenuItem(I18N.message("customactions")); - customActionsItem.setSubmenu(customActionsMenu); - return customActionsItem; - } - - private void prepareCustomActionMenuItem(final long folderId, GUIMenu menuAction, Menu customActionsMenu) { - MenuItem actionItem = new MenuItem(I18N.message(menuAction.getName())); - customActionsMenu.addItem(actionItem); - - actionItem.addClickHandler(event -> - /** - * Check on the server if the action has been modified - */ - SecurityService.Instance.get().getMenu(menuAction.getId(), I18N.getLocale(), new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(GUIMenu action) { - Session.get().getUser().updateCustomAction(action); - - if ((action.getRoutineId() == null || action.getRoutineId().longValue() == 0L) - && action.getAutomation() != null && !action.getAutomation().trim().isEmpty()) { - /* - * An automation cript is specified directly, so launch it's - * execution - */ - GUIAutomationRoutine routine = new GUIAutomationRoutine(); - routine.setAutomation(action.getAutomation()); - executeRoutine(folderId, null, routine); - } else if (action.getRoutineId() != null && action.getRoutineId().longValue() != 0L) { - AutomationService.Instance.get().getRoutine(action.getRoutineId(), new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(GUIAutomationRoutine routine) { - if (routine.getTemplateId() != null && routine.getTemplateId().longValue() != 0L) { - /* - * A routine with parameters is referenced, so - * open the input popup - */ - FillRoutineParams dialog = new FillRoutineParams(action.getName(), routine, folderId, - null); - dialog.show(); - } else { - /* - * A routine without parameters is referenced, - * so launch directly - */ - executeRoutine(folderId, null, routine); - } - } - }); - } - } - })); - } - - private void executeRoutine(long folderId, List docIds, GUIAutomationRoutine routine) { - AutomationService.Instance.get().execute(routine, docIds, folderId, new AsyncCallback<>() { - - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } - - @Override - public void onSuccess(Void arg0) { - // Nothing to do - } - }); - } - protected void handleDataArrived() { if (isFirstTime()) { onDataArrivedFirstTime(); diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/MergeDialog.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/MergeDialog.java index a5ae05218..ec85ec1d9 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/MergeDialog.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/MergeDialog.java @@ -2,13 +2,17 @@ import java.util.List; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.logicaldoc.gui.common.client.i18n.I18N; +import com.logicaldoc.gui.common.client.log.GuiLog; import com.logicaldoc.gui.common.client.util.LD; import com.logicaldoc.gui.frontend.client.folder.browser.FolderBrowser; +import com.logicaldoc.gui.frontend.client.services.FolderService; import com.smartgwt.client.types.HeaderControls; import com.smartgwt.client.widgets.Dialog; import com.smartgwt.client.widgets.toolbar.ToolStrip; import com.smartgwt.client.widgets.toolbar.ToolStripButton; +import com.smartgwt.client.widgets.tree.TreeNode; /** * This is the form used to copy some folders into another target folder @@ -45,12 +49,9 @@ public MergeDialog() { label = selectedIds.size() + " " + I18N.message("folders").toLowerCase(); LD.ask(I18N.message(MERGE), - I18N.message("mergeask", label, folders.getSelectedRecord().getAttributeAsString("name")), - (Boolean value) -> { - if (Boolean.TRUE.equals(value)) { - FolderNavigator.get().mergeTo( - Long.parseLong(folders.getSelectedRecord().getAttributeAsString("folderId"))); - } + I18N.message("mergeask", label, folders.getSelectedRecord().getAttributeAsString("name")), yes -> { + if (Boolean.TRUE.equals(yes)) + merge(folders.getSelectedRecord().getAttributeAsLong("folderId")); destroy(); }); }); @@ -62,4 +63,36 @@ public MergeDialog() { addMember(folders); addMember(buttons); } + + /** + * Merges the currently selected folders to a target folder + * + * @param targetFolderId The target folder + */ + private void merge(long targetFolderId) { + List ids = FolderNavigator.get().getSelectedIds(); + for (Long id : ids) { + TreeNode node = FolderNavigator.get().getTree().find(FolderNavigator.FOLDER_ID, (Object) id); + FolderNavigator.get().getTree().remove(node); + } + + LD.contactingServer(); + FolderService.Instance.get().merge(ids, targetFolderId, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + LD.clearPrompt(); + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void ret) { + LD.clearPrompt(); + TreeNode target = FolderNavigator.get().getTree().find(FolderNavigator.FOLDER_ID, + Long.toString(targetFolderId)); + if (target != null) + FolderNavigator.get().getTree().reloadChildren(target); + } + }); + } } \ No newline at end of file diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/browser/FolderTree.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/browser/FolderTree.java index 630ca8468..44fa3acfc 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/browser/FolderTree.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/browser/FolderTree.java @@ -1,6 +1,8 @@ package com.logicaldoc.gui.frontend.client.folder.browser; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.rpc.AsyncCallback; @@ -28,10 +30,12 @@ */ public class FolderTree extends TreeGrid { - protected static final String FOLDER_ID = "folderId"; + public static final String FOLDER_ID = "folderId"; protected static final String OPENED = "opened"; + public static final String PARENT_ID = "parentId"; + /** * String typed by the user inside the tree, to quickly select folders */ @@ -94,18 +98,17 @@ public FolderTree(FolderCursor cursor) { addCellClickHandler(event -> - FolderService.Instance.get().getFolder(getSelectedFolderId(), false, false, true, - new AsyncCallback<>() { - @Override - public void onFailure(Throwable caught) { - GuiLog.serverError(caught); - } + FolderService.Instance.get().getFolder(getSelectedFolderId(), false, false, true, new AsyncCallback<>() { + @Override + public void onFailure(Throwable caught) { + GuiLog.serverError(caught); + } - @Override - public void onSuccess(GUIFolder folder) { - cursor.onFolderSelected(folder); - } - })); + @Override + public void onSuccess(GUIFolder folder) { + cursor.onFolderSelected(folder); + } + })); } /* @@ -228,6 +231,38 @@ public long getSelectedFolderId() { return getSelectedRecord().getAttributeAsLong(FOLDER_ID); } + /** + * Gets all the IDs of the selected folders + * + * @return identifiers of folders + */ + public List getSelectedIds() { + ListGridRecord[] selection = getSelectedRecords(); + List ids = new ArrayList<>(); + for (ListGridRecord rec : selection) { + ids.add(rec.getAttributeAsLong(FOLDER_ID)); + } + return ids; + } + + /** + * Gets all the selected folders + * + * @return list of folders + */ + public List getSelectedFolders() { + ListGridRecord[] selection = getSelectedRecords(); + List folders = new ArrayList<>(); + for (ListGridRecord rec : selection) { + GUIFolder folder = new GUIFolder(); + folder.setId(rec.getAttributeAsLong(FOLDER_ID)); + folder.setName(rec.getAttributeAsString("name")); + folder.setParentId(rec.getAttributeAsLong(PARENT_ID)); + folders.add(folder); + } + return folders; + } + /** * Select the specified folder * diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/copy/FolderCopyDialog.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/copy/FolderCopyDialog.java index 418b46c79..8f4776b34 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/copy/FolderCopyDialog.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/folder/copy/FolderCopyDialog.java @@ -22,6 +22,7 @@ import com.smartgwt.client.widgets.form.fields.SelectItem; import com.smartgwt.client.widgets.form.fields.TextItem; import com.smartgwt.client.widgets.tree.TreeGrid; +import com.smartgwt.client.widgets.tree.TreeNode; /** * This is the form used to copy a folder into another path @@ -110,9 +111,9 @@ private void copyMultipleFolders(TreeGrid folders, List selectedSourceIds, LD.ask(I18N.message("copy"), I18N.message("copyask", Arrays.asList(label, folders.getSelectedRecord().getAttributeAsString("name"))), - (Boolean yes) -> { + yes -> { if (Boolean.TRUE.equals(yes)) { - FolderNavigator.get().copyTo(tagetFolderId, "true".equals(form.getValueAsString(FOLDERS_ONLY)), + copy(tagetFolderId, "true".equals(form.getValueAsString(FOLDERS_ONLY)), !securityOptionEnabled ? "inheritparentsec" : form.getValueAsString(SECURITY)); hide(); destroy(); @@ -134,12 +135,41 @@ public void onSuccess(GUIFolder sourceFolder) { sourceFolder.setAllowedPermissions(new GUIAccessControlEntry(GUIAccessControlEntry.PERMISSION_READ, GUIAccessControlEntry.PERMISSION_WRITE)); - FolderCopyDetailsDialog dialog = new FolderCopyDetailsDialog(sourceFolder, tagetFolderId, - form.getValueAsString(SECURITY), "true".equals(form.getValueAsString(FOLDERS_ONLY))); - dialog.show(); + new FolderCopyDetailsDialog(sourceFolder, tagetFolderId, form.getValueAsString(SECURITY), + "true".equals(form.getValueAsString(FOLDERS_ONLY))).show(); hide(); destroy(); } }); } + + /** + * Copies the currently selected folders to the new parent folder + * + * @param targetFolderId identifier of the parent folder + * @param foldersOnly to create just the folders + * @param securityOption how to setup the security for the new folder'none', + * 'inherit' or 'replicate' + */ + private void copy(long targetFolderId, boolean foldersOnly, String securityOption) { + final TreeNode target = FolderNavigator.get().getTree().findById(Long.toString(targetFolderId)); + + LD.contactingServer(); + FolderService.Instance.get().copyFolders(FolderNavigator.get().getSelectedIds(), targetFolderId, foldersOnly, + securityOption, null, new AsyncCallback<>() { + + @Override + public void onFailure(Throwable caught) { + LD.clearPrompt(); + GuiLog.serverError(caught); + } + + @Override + public void onSuccess(Void ret) { + LD.clearPrompt(); + if (target != null) + FolderNavigator.get().reload(); + } + }); + } } \ No newline at end of file diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationService.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationService.java index 06960dc93..75fc27b1d 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationService.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationService.java @@ -85,11 +85,11 @@ public interface AutomationService extends RemoteService { * database and the extended attributes of routine are * used as input parameters. * @param docIds selected documents (optional) - * @param folderId selected folders (optional) + * @param folderIds selected folders * * @throws ServerException an error happened in the server application */ - public void execute(GUIAutomationRoutine routine, List docIds, Long folderId) throws ServerException; + public void execute(GUIAutomationRoutine routine, List docIds, List folderIds) throws ServerException; public static class Instance { private static AutomationServiceAsync inst; diff --git a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationServiceAsync.java b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationServiceAsync.java index 740e8c35a..cdae925ef 100644 --- a/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationServiceAsync.java +++ b/logicaldoc-gui/src/main/java/com/logicaldoc/gui/frontend/client/services/AutomationServiceAsync.java @@ -22,5 +22,5 @@ public interface AutomationServiceAsync { void applyTriggersToTree(long rootId, AsyncCallback callback); - void execute(GUIAutomationRoutine routine, List docIds, Long folderId, AsyncCallback callback); + void execute(GUIAutomationRoutine routine, List docIds, List folderIds, AsyncCallback callback); } \ No newline at end of file diff --git a/logicaldoc-webapp/src/main/java/com/logicaldoc/web/data/FoldersDataServlet.java b/logicaldoc-webapp/src/main/java/com/logicaldoc/web/data/FoldersDataServlet.java index abe3590e2..8a170ac7b 100644 --- a/logicaldoc-webapp/src/main/java/com/logicaldoc/web/data/FoldersDataServlet.java +++ b/logicaldoc-webapp/src/main/java/com/logicaldoc/web/data/FoldersDataServlet.java @@ -112,6 +112,7 @@ private void printFolders(PrintWriter writer, Session session, long tenantId, St writer.print(""); writer.print("" + parent + "-" + rs.getLong(1) + ""); writer.print("" + rs.getLong(1) + ""); + writer.print("" + rs.getLong(2) + ""); writer.print("" + parent + ""); writer.print(""); writer.print("" + rs.getInt(4) + ""); @@ -160,11 +161,11 @@ private void printFoldersWithDocs(PrintWriter writer, String parent, Folder pare params.put("parentId", parentFolder.getId()); SqlRowSet rs = folderDao.queryForRowSet(query.toString(), params, null); if (rs != null) - printFoldersWithDocs(writer, rs, parent); + printFoldersWithDocs(writer, rs, parent, parentFolder.getId()); } } - private void printFoldersWithDocs(PrintWriter writer, SqlRowSet rs, String parent) { + private void printFoldersWithDocs(PrintWriter writer, SqlRowSet rs, String parent, long parentId) { while (rs.next()) { Date now = new Date(); boolean published = (rs.getInt(4) == 1) && (rs.getDate(5) == null || now.after(rs.getDate(5))) @@ -172,6 +173,7 @@ private void printFoldersWithDocs(PrintWriter writer, SqlRowSet rs, String paren writer.print(""); writer.print("d-" + rs.getLong(1) + ""); writer.print("d-" + rs.getLong(1) + ""); + writer.print("" + parentId + ""); writer.print("" + parent + ""); writer.print(""); writer.print("file"); diff --git a/logicaldoc-webapp/src/main/java/com/logicaldoc/web/websockets/EventEndpoint.java b/logicaldoc-webapp/src/main/java/com/logicaldoc/web/websockets/EventEndpoint.java index cdbcda95c..7e75728f3 100644 --- a/logicaldoc-webapp/src/main/java/com/logicaldoc/web/websockets/EventEndpoint.java +++ b/logicaldoc-webapp/src/main/java/com/logicaldoc/web/websockets/EventEndpoint.java @@ -174,6 +174,7 @@ private WebsocketMessage prepareMessage(History event) throws PersistenceExcepti message.setComment(event.getComment()); message.setDate(event.getDate()); message.setId(event.getId()); + message.setTenantId(event.getTenantId()); if (event instanceof UserHistory userHistory) message.setAuthor(userHistory.getAuthor());