From a180165f743bcea9d49c3dff32ee225aeb61b6fa Mon Sep 17 00:00:00 2001 From: Thomas Low Date: Thu, 5 Dec 2024 13:01:16 +0000 Subject: [PATCH 1/4] First draft for multiple tree node drag & drop in structure tree. --- .../dataeditor/AddDocStrucTypeDialog.java | 13 +- .../forms/dataeditor/DataEditorForm.java | 8 +- .../forms/dataeditor/PaginationPanel.java | 6 +- .../forms/dataeditor/StructurePanel.java | 333 ++++++++++++------ .../forms/dataeditor/UploadFileDialog.java | 4 +- .../dataeditor/DataEditorService.java | 4 +- .../includes/metadataEditor/gallery.xhtml | 6 +- .../metadataEditor/logicalMetadata.xhtml | 2 +- .../metadataEditor/logicalStructure.xhtml | 27 +- .../metadataEditor/physicalMetadata.xhtml | 2 +- 10 files changed, 254 insertions(+), 151 deletions(-) diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/AddDocStrucTypeDialog.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/AddDocStrucTypeDialog.java index 48e7d46f484..167c83f8a36 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/AddDocStrucTypeDialog.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/AddDocStrucTypeDialog.java @@ -19,6 +19,7 @@ import static org.kitodo.production.metadata.InsertionPosition.PARENT_OF_CURRENT_ELEMENT; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; @@ -181,10 +182,10 @@ private void addSingleDocStruc(boolean selectViews) { } } dataEditor.refreshStructurePanel(); - TreeNode selectedLogicalTreeNode = dataEditor.getStructurePanel().updateLogicalNodeSelectionRecursive(newStructure, + List selectedLogicalTreeNodes = dataEditor.getStructurePanel().updateLogicalNodeSelectionRecursive(newStructure, this.dataEditor.getStructurePanel().getLogicalTree()); - if (Objects.nonNull(selectedLogicalTreeNode)) { - this.dataEditor.getStructurePanel().setSelectedLogicalNode(selectedLogicalTreeNode); + if (Objects.nonNull(selectedLogicalTreeNodes)) { + this.dataEditor.getStructurePanel().setSelectedLogicalNodes(selectedLogicalTreeNodes); this.dataEditor.getMetadataPanel().showLogical(this.dataEditor.getSelectedStructure()); dataEditor.refreshStructurePanel(); } @@ -435,13 +436,13 @@ public void prepare() { private void checkSelectedLogicalNode() { //If a view is selected in logical tree then the 'selectedLogicalNode' will be set to the parent of this view - TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode(); + TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNodeIfSingle(); if (Objects.nonNull(selectedLogicalNode) && selectedLogicalNode.getData() instanceof StructureTreeNode) { StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); if (structureTreeNode.getDataObject() instanceof View) { if (Objects.nonNull(selectedLogicalNode.getParent())) { previouslySelectedLogicalNode = selectedLogicalNode; - dataEditor.getStructurePanel().setSelectedLogicalNode(selectedLogicalNode.getParent()); + dataEditor.getStructurePanel().setSelectedLogicalNodes(Arrays.asList(selectedLogicalNode.getParent())); } } } @@ -593,7 +594,7 @@ public void resetValues() { selectFirstPageOnAddNode = null; selectLastPageOnAddNode = null; if (Objects.nonNull(previouslySelectedLogicalNode)) { - dataEditor.getStructurePanel().setSelectedLogicalNode(previouslySelectedLogicalNode); + dataEditor.getStructurePanel().setSelectedLogicalNodes(Arrays.asList(previouslySelectedLogicalNode)); previouslySelectedLogicalNode = null; } } diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/DataEditorForm.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/DataEditorForm.java index fb64e70134d..495b6a14306 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/DataEditorForm.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/DataEditorForm.java @@ -433,7 +433,9 @@ private void init() { structurePanel.getSeveralAssignments().addAll(severalAssignments); structurePanel.show(); - structurePanel.getSelectedLogicalNode().setSelected(true); + for (TreeNode node : structurePanel.getSelectedLogicalNodes()) { + node.setSelected(true); + } structurePanel.getSelectedPhysicalNode().setSelected(true); metadataPanel.showLogical(getSelectedStructure()); metadataPanel.showPhysical(getSelectedPhysicalDivision()); @@ -647,7 +649,7 @@ public void deleteStructure() { * clicked on the context menu entry to delete the physical division. */ public void deletePhysicalDivision() { - structurePanel.deleteSelectedPhysicalDivision(); + structurePanel.deleteSelectedPhysicalDivisions(); updateNumberOfScans(); } @@ -1330,7 +1332,7 @@ public String getMetadataFileLoadingError() { */ public boolean canUpdateMetadata() { try { - return DataEditorService.canUpdateCatalogMetadata(process, workpiece, structurePanel.getSelectedLogicalNode()); + return DataEditorService.canUpdateCatalogMetadata(process, workpiece, structurePanel.getSelectedLogicalNodeIfSingle()); } catch (IOException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); return false; diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/PaginationPanel.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/PaginationPanel.java index 623629c8884..e873a1a45c3 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/PaginationPanel.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/PaginationPanel.java @@ -371,14 +371,14 @@ public void startPaginationClick() { private void updateMetadataPanel() { if (dataEditor.getSelectedStructure().isPresent()) { dataEditor.getMetadataPanel().showLogical(dataEditor.getSelectedStructure()); - } else if (Objects.nonNull(dataEditor.getStructurePanel().getSelectedLogicalNode()) - && dataEditor.getStructurePanel().getSelectedLogicalNode().getData() instanceof StructureTreeNode + } /* else if (Objects.nonNull(dataEditor.getStructurePanel().getSelectedLogicalNodes()) + && dataEditor.getStructurePanel().getSelectedLogicalNodes().getData() instanceof StructureTreeNode && Objects.nonNull(dataEditor.getStructurePanel().getSelectedLogicalNode().getData()) && ((StructureTreeNode) dataEditor.getStructurePanel().getSelectedLogicalNode().getData()) .getDataObject() instanceof View) { View view = (View) ((StructureTreeNode) dataEditor.getStructurePanel().getSelectedLogicalNode().getData()).getDataObject(); dataEditor.getMetadataPanel().showPageInLogical(view.getPhysicalDivision()); - } + }*/ } /** diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java index 8cb717c7e76..017a9603159 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java @@ -70,7 +70,7 @@ public class StructurePanel implements Serializable { * If changing the tree node fails, we need this value to undo the user’s * select action. */ - private TreeNode previouslySelectedLogicalNode; + private List previouslySelectedLogicalNodes; /** * If changing the tree node fails, we need this value to undo the user’s @@ -78,7 +78,7 @@ public class StructurePanel implements Serializable { */ private TreeNode previouslySelectedPhysicalNode; - private TreeNode selectedLogicalNode; + private TreeNode[] selectedLogicalNodes; private TreeNode selectedPhysicalNode; @@ -164,9 +164,9 @@ public class StructurePanel implements Serializable { public void clear() { logicalTree = null; physicalTree = null; - selectedLogicalNode = null; + selectedLogicalNodes = new TreeNode[] {}; selectedPhysicalNode = null; - previouslySelectedLogicalNode = null; + previouslySelectedLogicalNodes = new ArrayList<>(); previouslySelectedPhysicalNode = null; structure = null; subfoldersCache = new HashMap<>(); @@ -228,10 +228,18 @@ private void getAllSubViews(LogicalDivision selectedStructure, Collection } } - void deleteSelectedPhysicalDivision() { - if (Objects.nonNull(selectedLogicalNode) && MEDIA_PARTIAL_NODE_TYPE.equals( - selectedLogicalNode.getType()) && selectedLogicalNode.getData() instanceof StructureTreeNode) { - StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); + /** + * Delete a single physical division that is part of the current selection. + * + * @param treeNode the PrimeFaces treeNode that is currently selected for deletion + */ + private void deleteSelectedPhysicalDivision(TreeNode treeNode) { + if (Objects.isNull(treeNode)) { + // there is nothing to do + return; + } + if (MEDIA_PARTIAL_NODE_TYPE.equals(treeNode.getType()) && treeNode.getData() instanceof StructureTreeNode) { + StructureTreeNode structureTreeNode = (StructureTreeNode) treeNode.getData(); PhysicalDivision physicalDivision = ((View) structureTreeNode.getDataObject()).getPhysicalDivision(); for (LogicalDivision structuralElement : physicalDivision.getLogicalDivisions()) { structuralElement.getViews().removeIf(view -> view.getPhysicalDivision().equals(physicalDivision)); @@ -258,6 +266,19 @@ void deleteSelectedPhysicalDivision() { } } } + } + + /** + * Delete all currently selected physical divisons. + */ + public void deleteSelectedPhysicalDivisions() { + if (Objects.isNull(selectedLogicalNodes)) { + // there is nothing to do + return; + } + for (TreeNode selectedLogicalNode : selectedLogicalNodes) { + deleteSelectedPhysicalDivision(selectedLogicalNode); + } int i = 1; for (PhysicalDivision physicalDivision : dataEditor.getWorkpiece().getAllPhysicalDivisionChildrenSortedFilteredByPageAndTrack()) { @@ -290,25 +311,65 @@ public boolean deletePhysicalDivision(PhysicalDivision physicalDivision) { } /** - * Get selected logical TreeNode. + * Get selected logical TreeNodes if it is the only selected TreeNode + * (e.g. when opening the context menu). + * + * @return TreeNode instance if it is the only selected node or null + */ + public TreeNode getSelectedLogicalNodeIfSingle() { + List nodes = getSelectedLogicalNodes(); + if (Objects.nonNull(nodes) && nodes.size() == 1) { + return nodes.get(0); + } + return null; + } + + /** + * Get selected logical TreeNodes as List. + * + * @return value of selectedLogicalNodes as List + */ + public List getSelectedLogicalNodes() { + return Arrays.asList(selectedLogicalNodes); + } + + /** + * Get selected logical TreeNodes as Array (as required by PrimeFaces). * - * @return value of selectedLogicalNode + * @return value of selectedLogicalNodes as array */ - public TreeNode getSelectedLogicalNode() { - return selectedLogicalNode; + public TreeNode[] getSelectedLogicalNodesAsArray() { + return selectedLogicalNodes; } /** - * Set selected logical TreeNode. + * Set selected logical TreeNodes from Array (as required by PrimeFaces). * * @param selected - * TreeNode that will be selected + * array of TreeNodes that will be selected */ - public void setSelectedLogicalNode(TreeNode selected) { + public void setSelectedLogicalNodesAsArray(TreeNode[] selected) { if (Objects.nonNull(selected)) { - this.selectedLogicalNode = selected; - expandNode(selected.getParent()); + this.selectedLogicalNodes = selected; + for (TreeNode node : selected) { + if (Objects.nonNull(node)) { + expandNode(node.getParent()); + } + } } + + } + + /** + * Set selected logical TreeNodes from Collection. + * + * @param selected + * collection of TreeNodes that will be selected + */ + public void setSelectedLogicalNodes(List selected) { + if (Objects.nonNull(selected)) { + this.setSelectedLogicalNodesAsArray((TreeNode[])selected.toArray(new TreeNode[selected.size()])); + } } /** @@ -332,8 +393,13 @@ public void setSelectedPhysicalNode(TreeNode selectedPhysicalNode) { } } + /** + * Return the currently selected logical divison if it is the only selected structure element. + * @return + */ Optional getSelectedStructure() { - if (Objects.isNull(selectedLogicalNode)) { + TreeNode selectedLogicalNode = getSelectedLogicalNodeIfSingle(); + if (Objects.isNull(selectedLogicalNode) || !(selectedLogicalNode.getData() instanceof StructureTreeNode)) { return Optional.empty(); } StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); @@ -489,29 +555,30 @@ private static PhysicalDivision preservePhysicalRecursive(TreeNode treeNode) { * if true, keeps the currently selected node(s) */ public void show(boolean keepSelection) { - if (keepSelection) { - String logicalRowKey = null; - if (Objects.nonNull(selectedLogicalNode)) { - logicalRowKey = selectedLogicalNode.getRowKey(); - } - String physicalRowKey = null; - if (Objects.nonNull(selectedPhysicalNode)) { - physicalRowKey = selectedPhysicalNode.getRowKey(); - } - TreeNode keepSelectedLogicalNode = selectedLogicalNode; - TreeNode keepSelectedPhysicalNode = selectedPhysicalNode; - show(); - selectedLogicalNode = keepSelectedLogicalNode; - selectedPhysicalNode = keepSelectedPhysicalNode; - if (Objects.nonNull(logicalRowKey)) { - restoreSelection(logicalRowKey, this.logicalTree); - } - if (Objects.nonNull(physicalRowKey)) { - restoreSelection(physicalRowKey, this.physicalTree); - } - } else { + if (!keepSelection) { show(); + return; + } + + Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); + + String physicalRowKey = null; + if (Objects.nonNull(selectedPhysicalNode)) { + physicalRowKey = selectedPhysicalNode.getRowKey(); } + + List keepSelectedLogicalNodes = getSelectedLogicalNodes(); + TreeNode keepSelectedPhysicalNode = selectedPhysicalNode; + show(); + setSelectedLogicalNodes(keepSelectedLogicalNodes); + selectedPhysicalNode = keepSelectedPhysicalNode; + restoreSelectionFromRowKeys(logicalRowKeys, this.logicalTree); + + // ------------------------ TODO TODO TODO -------------- + /*if (Objects.nonNull(physicalRowKey)) { + restoreSelection(physicalRowKey, this.physicalTree); + }*/ + } /** @@ -529,21 +596,30 @@ public void show() { this.physicalTree = buildMediaTree(dataEditor.getWorkpiece().getPhysicalStructure()); updatePhysicalNodeExpansionStates(this.physicalTree, this.previousExpansionStatesPhysicalTree); - this.selectedLogicalNode = logicalTree.getChildren().get(logicalTree.getChildCount() - 1); + setSelectedLogicalNodes(Arrays.asList(logicalTree.getChildren().get(logicalTree.getChildCount() - 1))); this.selectedPhysicalNode = physicalTree.getChildren().get(0); - this.previouslySelectedLogicalNode = selectedLogicalNode; + this.previouslySelectedLogicalNodes = getSelectedLogicalNodes(); this.previouslySelectedPhysicalNode = selectedPhysicalNode; dataEditor.checkForChanges(); } - private void restoreSelection(String rowKey, TreeNode parentNode) { + private Set getTreeNodeRowKeys(Collection nodes) { + HashSet logicalRowKeys = new HashSet<>(); + if (Objects.nonNull(nodes)) { + for (TreeNode node: nodes) { + logicalRowKeys.add(node.getRowKey()); + } + } + return logicalRowKeys; + } + + private void restoreSelectionFromRowKeys(Set rowKeys, TreeNode parentNode) { for (TreeNode childNode : parentNode.getChildren()) { - if (Objects.nonNull(childNode) && rowKey.equals(childNode.getRowKey())) { + if (Objects.nonNull(childNode) && rowKeys.contains(childNode.getRowKey())) { childNode.setSelected(true); - break; } else { childNode.setSelected(false); - restoreSelection(rowKey, childNode); + restoreSelectionFromRowKeys(rowKeys, childNode); } } } @@ -957,11 +1033,14 @@ public void treeLogicalSelect(NodeSelectEvent event) { * JSF at this point. */ try { - dataEditor.switchStructure(event.getTreeNode().getData(), true); - previouslySelectedLogicalNode = selectedLogicalNode; + TreeNode selectedTreeNode = getSelectedLogicalNodeIfSingle(); + if (Objects.nonNull(selectedTreeNode)) { + dataEditor.switchStructure(selectedTreeNode.getData(), true); + } + previouslySelectedLogicalNodes = getSelectedLogicalNodes(); } catch (NoSuchMetadataFieldException e) { Helper.setErrorMessage(e.getLocalizedMessage(), logger, e); - selectedLogicalNode = previouslySelectedLogicalNode; + setSelectedLogicalNodes(previouslySelectedLogicalNodes); } } @@ -1013,11 +1092,15 @@ void updatePhysicalNodeSelection(GalleryMediaContent galleryMediaContent) { } void updateLogicalNodeSelection(GalleryMediaContent galleryMediaContent, LogicalDivision structure) { - if (Objects.nonNull(previouslySelectedLogicalNode)) { - previouslySelectedLogicalNode.setSelected(false); + if (Objects.nonNull(previouslySelectedLogicalNodes)) { + for (TreeNode node : previouslySelectedLogicalNodes) { + node.setSelected(false); + } } - if (Objects.nonNull(selectedLogicalNode)) { - selectedLogicalNode.setSelected(false); + if (Objects.nonNull(selectedLogicalNodes)) { + for (TreeNode node : selectedLogicalNodes) { + node.setSelected(false); + } } if (Objects.nonNull(this.logicalTree)) { if (Objects.isNull(structure)) { @@ -1027,15 +1110,15 @@ void updateLogicalNodeSelection(GalleryMediaContent galleryMediaContent, Logical } } if (Objects.nonNull(structure)) { - TreeNode selectedTreeNode; + List selectedTreeNodes; if (!this.logicalStructureTreeContainsMedia()) { - selectedTreeNode = updateLogicalNodeSelectionRecursive(structure, logicalTree); + selectedTreeNodes = updateLogicalNodeSelectionRecursive(structure, logicalTree); } else { - selectedTreeNode = updatePhysSelectionInLogTreeRecursive(galleryMediaContent.getView().getPhysicalDivision(), structure, + selectedTreeNodes = updatePhysSelectionInLogTreeRecursive(galleryMediaContent.getView().getPhysicalDivision(), structure, logicalTree); } - if (Objects.nonNull(selectedTreeNode)) { - setSelectedLogicalNode(selectedTreeNode); + if (Objects.nonNull(selectedTreeNodes)) { + setSelectedLogicalNodes(selectedTreeNodes); } else { Helper.setErrorMessage("Unable to update node selection in logical structure!"); } @@ -1044,18 +1127,22 @@ void updateLogicalNodeSelection(GalleryMediaContent galleryMediaContent, Logical } void updateLogicalNodeSelection(LogicalDivision logicalDivision) { - if (Objects.nonNull(previouslySelectedLogicalNode)) { - previouslySelectedLogicalNode.setSelected(false); + if (Objects.nonNull(previouslySelectedLogicalNodes)) { + for (TreeNode node : previouslySelectedLogicalNodes) { + node.setSelected(false); + } } - if (Objects.nonNull(selectedLogicalNode)) { - selectedLogicalNode.setSelected(false); + if (Objects.nonNull(selectedLogicalNodes)) { + for (TreeNode node : selectedLogicalNodes) { + node.setSelected(false); + } } if (Objects.nonNull(logicalTree)) { - TreeNode selectedTreeNode = updateLogicalNodeSelectionRecursive(logicalDivision, logicalTree); - if (Objects.nonNull(selectedTreeNode)) { - setSelectedLogicalNode(selectedTreeNode); + List selectedTreeNodes = updateLogicalNodeSelectionRecursive(logicalDivision, logicalTree); + if (Objects.nonNull(selectedTreeNodes) && selectedTreeNodes.size() > 0) { + setSelectedLogicalNodes(selectedTreeNodes); try { - dataEditor.switchStructure(selectedTreeNode.getData(), false); + dataEditor.switchStructure(selectedTreeNodes.get(0).getData(), false); } catch (NoSuchMetadataFieldException e) { logger.error(e.getLocalizedMessage()); } @@ -1071,20 +1158,17 @@ void updateLogicalNodeSelection(LogicalDivision logicalDivision) { * @param treeNode the logical structure tree * @return the TreeNode that will be selected */ - public TreeNode updateLogicalNodeSelectionRecursive(LogicalDivision structure, TreeNode treeNode) { - TreeNode matchingTreeNode = null; + public List updateLogicalNodeSelectionRecursive(LogicalDivision structure, TreeNode treeNode) { + List matchingTreeNodes = new ArrayList<>(); for (TreeNode currentTreeNode : treeNode.getChildren()) { if (treeNodeMatchesStructure(structure, currentTreeNode)) { currentTreeNode.setSelected(true); - matchingTreeNode = currentTreeNode; + matchingTreeNodes.add(currentTreeNode); } else { - matchingTreeNode = updateLogicalNodeSelectionRecursive(structure, currentTreeNode); - } - if (Objects.nonNull(matchingTreeNode)) { - break; + matchingTreeNodes.addAll(updateLogicalNodeSelectionRecursive(structure, currentTreeNode)); } } - return matchingTreeNode; + return matchingTreeNodes; } private TreeNode updatePhysicalNodeSelectionRecursive(GalleryMediaContent galleryMediaContent, TreeNode treeNode) { @@ -1107,9 +1191,9 @@ private TreeNode updatePhysicalNodeSelectionRecursive(GalleryMediaContent galler return matchingTreeNode; } - private TreeNode updatePhysSelectionInLogTreeRecursive(PhysicalDivision selectedPhysicalDivision, LogicalDivision parentElement, + private List updatePhysSelectionInLogTreeRecursive(PhysicalDivision selectedPhysicalDivision, LogicalDivision parentElement, TreeNode treeNode) { - TreeNode matchingTreeNode = null; + List matchingTreeNodes = new ArrayList<>(); for (TreeNode currentTreeNode : treeNode.getChildren()) { if (treeNode.getData() instanceof StructureTreeNode && Objects.nonNull(((StructureTreeNode) treeNode.getData()).getDataObject()) @@ -1120,16 +1204,13 @@ private TreeNode updatePhysSelectionInLogTreeRecursive(PhysicalDivision selected && ((View) ((StructureTreeNode) currentTreeNode.getData()).getDataObject()).getPhysicalDivision() .equals(selectedPhysicalDivision)) { currentTreeNode.setSelected(true); - matchingTreeNode = currentTreeNode; + matchingTreeNodes.add(currentTreeNode); } else { currentTreeNode.setSelected(false); - matchingTreeNode = updatePhysSelectionInLogTreeRecursive(selectedPhysicalDivision, parentElement, currentTreeNode); - } - if (Objects.nonNull(matchingTreeNode)) { - break; + matchingTreeNodes.addAll(updatePhysSelectionInLogTreeRecursive(selectedPhysicalDivision, parentElement, currentTreeNode)); } } - return matchingTreeNode; + return matchingTreeNodes; } private boolean treeNodeMatchesGalleryMediaContent(GalleryMediaContent galleryMediaContent, TreeNode treeNode) { @@ -1194,34 +1275,37 @@ public void onNodeExpand(NodeExpandEvent event) { * event triggering this callback function */ public void onDragDrop(TreeDragDropEvent event) { - Object dragNodeObject = event.getDragNode().getData(); - Object dropNodeObject = event.getDropNode().getData(); - - expandNode(event.getDropNode()); - - try { - StructureTreeNode dropNode = (StructureTreeNode) dropNodeObject; - StructureTreeNode dragNode = (StructureTreeNode) dragNodeObject; - if (dropNode.isLinked()) { - Helper.setErrorMessage("dataEditor.dragNDropLinkError"); - show(); - } - else if (dragNode.getDataObject() instanceof LogicalDivision - && dropNode.getDataObject() instanceof LogicalDivision) { - checkLogicalDragDrop(dragNode, dropNode); - } else if (dragNode.getDataObject() instanceof PhysicalDivision - && dropNode.getDataObject() instanceof PhysicalDivision) { - checkPhysicalDragDrop(dragNode, dropNode); - } else if (dragNode.getDataObject() instanceof View - && dropNode.getDataObject() instanceof LogicalDivision) { - movePageNode(event, dropNode, dragNode); - } else { - Helper.setErrorMessage( - Helper.getTranslation("dataEditor.dragNDropError", dragNode.getLabel(), dropNode.getLabel())); - show(); + TreeNode dropTreeNode = event.getDropNode(); + Object dropNodeObject = dropTreeNode.getData(); + expandNode(dropTreeNode); + + for (TreeNode dragTreeNode : event.getDragNodes()) { + Object dragNodeObject = dragTreeNode.getData(); + try { + StructureTreeNode dropNode = (StructureTreeNode) dropNodeObject; + StructureTreeNode dragNode = (StructureTreeNode) dragNodeObject; + + if (dropNode.isLinked()) { + Helper.setErrorMessage("dataEditor.dragNDropLinkError"); + show(); + } + else if (dragNode.getDataObject() instanceof LogicalDivision + && dropNode.getDataObject() instanceof LogicalDivision) { + checkLogicalDragDrop(dragNode, dropNode); + } else if (dragNode.getDataObject() instanceof PhysicalDivision + && dropNode.getDataObject() instanceof PhysicalDivision) { + checkPhysicalDragDrop(dragNode, dropNode); + } else if (dragNode.getDataObject() instanceof View + && dropNode.getDataObject() instanceof LogicalDivision) { + movePageNode(dragTreeNode, dropTreeNode, dropNode, dragNode); + } else { + Helper.setErrorMessage( + Helper.getTranslation("dataEditor.dragNDropError", dragNode.getLabel(), dropNode.getLabel())); + show(); + } + } catch (Exception exception) { + logger.error(exception.getLocalizedMessage(), exception); } - } catch (Exception exception) { - logger.error(exception.getLocalizedMessage()); } } @@ -1253,13 +1337,13 @@ LogicalDivision getPageStructure(View view, LogicalDivision parent) { * * @param event * TreeDragDropEvent triggering 'movePageNode' - * @param dropNode + * @param dropStructureNode * StructureTreeNode containing the Structural Element to which the page is moved - * @param dragNode + * @param dragStructureNode * StructureTreeNode containing the View/Page that is moved */ - private void movePageNode(TreeDragDropEvent event, StructureTreeNode dropNode, StructureTreeNode dragNode) throws Exception { - TreeNode dragParent = event.getDragNode().getParent(); + private void movePageNode(TreeNode dragTreeNode, TreeNode dropTreeNode, StructureTreeNode dropStructureNode, StructureTreeNode dragStructureNode) throws Exception { + TreeNode dragParent = dragTreeNode.getParent(); if (dragParent.getData() instanceof StructureTreeNode) { StructureTreeNode dragParentTreeNode = (StructureTreeNode) dragParent.getData(); if (dragParentTreeNode.getDataObject() instanceof LogicalDivision) { @@ -1267,17 +1351,17 @@ private void movePageNode(TreeDragDropEvent event, StructureTreeNode dropNode, S // Until fixed dropping nodes onto other nodes will produce random drop indices. preserveLogicalAndPhysical(); show(); - expandNode(event.getDropNode()); + expandNode(dropTreeNode); dataEditor.getGalleryPanel().updateStripes(); dataEditor.getPaginationPanel().show(); return; } else { Helper.setErrorMessage( - Helper.getTranslation("dataEditor.dragNDropError", dragNode.getLabel(), dropNode.getLabel())); + Helper.getTranslation("dataEditor.dragNDropError", dragStructureNode.getLabel(), dropStructureNode.getLabel())); } } else { Helper.setErrorMessage( - Helper.getTranslation("dataEditor.dragNDropError", dragNode.getLabel(), dropNode.getLabel())); + Helper.getTranslation("dataEditor.dragNDropError", dragStructureNode.getLabel(), dropStructureNode.getLabel())); } show(); } @@ -1766,8 +1850,9 @@ public int getMultipleAssignmentsIndex(StructureTreeNode treeNode) { * @return {@code true} when the PhysicalDivision is assigned to more than one logical element */ public boolean isAssignedSeveralTimes() { - if (Objects.nonNull(selectedLogicalNode) && selectedLogicalNode.getData() instanceof StructureTreeNode) { - StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); + TreeNode selected = getSelectedLogicalNodeIfSingle(); + if (Objects.nonNull(selected) && selected.getData() instanceof StructureTreeNode) { + StructureTreeNode structureTreeNode = (StructureTreeNode) selected.getData(); if (structureTreeNode.getDataObject() instanceof View) { View view = (View) structureTreeNode.getDataObject(); return view.getPhysicalDivision().getLogicalDivisions().size() > 1; @@ -1856,6 +1941,10 @@ private TreeNode findNextLogicalNodeForViewAssignmentRecursive(TreeNode node) { * @return {@code true} if the PhysicalDivision can be assigned to the next LogicalDivision */ public boolean isAssignableSeveralTimes() { + TreeNode selectedLogicalNode = getSelectedLogicalNodeIfSingle(); + if (Objects.isNull(selectedLogicalNode)) { + return false; + } TreeNode nextLogical = findNextLogicalNodeForViewAssignment(selectedLogicalNode); if (Objects.nonNull(nextLogical)) { // check whether first child is already view of current node (too avoid adding views multiple times) @@ -1879,6 +1968,11 @@ public boolean isAssignableSeveralTimes() { * Assign selected Node's PhysicalDivision to the next LogicalDivision. */ public void assign() { + TreeNode selectedLogicalNode = getSelectedLogicalNodeIfSingle(); + if (Objects.isNull(selectedLogicalNode)) { + logger.error("assign called without selection or too many selected, should not happen"); + return; + } TreeNode nextLogical = findNextLogicalNodeForViewAssignment(selectedLogicalNode); if (Objects.nonNull(nextLogical)) { View view = (View) ((StructureTreeNode) selectedLogicalNode.getData()).getDataObject(); @@ -1899,6 +1993,11 @@ public void assign() { * This does not remove it from other LogicalDivisions. */ public void unassign() { + TreeNode selectedLogicalNode = getSelectedLogicalNodeIfSingle(); + if (Objects.isNull(selectedLogicalNode)) { + logger.error("unassign called without selection or too many selected, should not happen"); + return; + } if (isAssignedSeveralTimes()) { StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); View view = (View) structureTreeNode.getDataObject(); diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/UploadFileDialog.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/UploadFileDialog.java index b269b1ec2b1..5d2f93e3ec1 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/UploadFileDialog.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/UploadFileDialog.java @@ -258,7 +258,7 @@ private URI getFolderURI(Folder folder) { } private void initPosition() { - TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode(); + TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNodeIfSingle(); if (Objects.nonNull(selectedLogicalNode) && selectedLogicalNode.getData() instanceof StructureTreeNode) { StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); @@ -283,7 +283,7 @@ private void initPosition() { private void preparePossiblePositions() { possiblePositions = new ArrayList<>(); - TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode(); + TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNodeIfSingle(); if (Objects.nonNull(selectedLogicalNode) && selectedLogicalNode.getData() instanceof StructureTreeNode) { StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData(); diff --git a/Kitodo/src/main/java/org/kitodo/production/services/dataeditor/DataEditorService.java b/Kitodo/src/main/java/org/kitodo/production/services/dataeditor/DataEditorService.java index 6538efc8b61..9a3f302413f 100644 --- a/Kitodo/src/main/java/org/kitodo/production/services/dataeditor/DataEditorService.java +++ b/Kitodo/src/main/java/org/kitodo/production/services/dataeditor/DataEditorService.java @@ -264,10 +264,10 @@ public static StructuralElementViewInterface getStructuralElementView(DataEditor dataEditor.getAcquisitionStage(), dataEditor.getPriorityList()); } - TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode(); + TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNodeIfSingle(); if (Objects.isNull(selectedLogicalNode)) { - throw new IllegalStateException("No logical node selected!"); + return null; } if (!(selectedLogicalNode.getData() instanceof StructureTreeNode)) { diff --git a/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/gallery.xhtml b/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/gallery.xhtml index d5933c33e3b..18f234fee94 100644 --- a/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/gallery.xhtml +++ b/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/gallery.xhtml @@ -88,7 +88,7 @@ styleClass="pageList" binding="#{currentElement}"> - @@ -131,7 +131,7 @@ @@ -209,7 +209,7 @@ diff --git a/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/logicalStructure.xhtml b/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/logicalStructure.xhtml index 5339212ce60..e778ebdb07a 100644 --- a/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/logicalStructure.xhtml +++ b/Kitodo/src/main/webapp/WEB-INF/templates/includes/metadataEditor/logicalStructure.xhtml @@ -64,8 +64,9 @@ var="logicalNode" nodeVar="defaultTreeNode" styleClass="focusable" - selectionMode="single" - selection="#{DataEditorForm.structurePanel.selectedLogicalNode}" + selectionMode="multiple" + multipleDrag="true" + selection="#{DataEditorForm.structurePanel.selectedLogicalNodesAsArray}" draggable="#{not readOnly and SecurityAccessController.hasAuthorityToEditProcessStructureData()}" droppable="#{not readOnly and SecurityAccessController.hasAuthorityToEditProcessStructureData()}" dragdropScope="logicalTree" @@ -152,7 +153,7 @@ - Date: Thu, 5 Dec 2024 13:15:44 +0000 Subject: [PATCH 2/4] Fix checkstyle issues in StructurePanel. --- .../forms/dataeditor/StructurePanel.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java index 017a9603159..891d74f0903 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java @@ -395,7 +395,7 @@ public void setSelectedPhysicalNode(TreeNode selectedPhysicalNode) { /** * Return the currently selected logical divison if it is the only selected structure element. - * @return + * @return LogicalDivison as Optional instance */ Optional getSelectedStructure() { TreeNode selectedLogicalNode = getSelectedLogicalNodeIfSingle(); @@ -558,15 +558,14 @@ public void show(boolean keepSelection) { if (!keepSelection) { show(); return; - } + } - Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); - String physicalRowKey = null; if (Objects.nonNull(selectedPhysicalNode)) { physicalRowKey = selectedPhysicalNode.getRowKey(); } + Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); List keepSelectedLogicalNodes = getSelectedLogicalNodes(); TreeNode keepSelectedPhysicalNode = selectedPhysicalNode; show(); @@ -1114,8 +1113,11 @@ void updateLogicalNodeSelection(GalleryMediaContent galleryMediaContent, Logical if (!this.logicalStructureTreeContainsMedia()) { selectedTreeNodes = updateLogicalNodeSelectionRecursive(structure, logicalTree); } else { - selectedTreeNodes = updatePhysSelectionInLogTreeRecursive(galleryMediaContent.getView().getPhysicalDivision(), structure, - logicalTree); + selectedTreeNodes = updatePhysSelectionInLogTreeRecursive( + galleryMediaContent.getView().getPhysicalDivision(), + structure, + logicalTree + ); } if (Objects.nonNull(selectedTreeNodes)) { setSelectedLogicalNodes(selectedTreeNodes); @@ -1335,14 +1337,21 @@ LogicalDivision getPageStructure(View view, LogicalDivision parent) { * Move page encapsulated in given StructureTreeNode 'dragNode' to Structural Element encapsulated in given * StructureTreeNode 'dropNode' at index encoded in given TreeDragDropEvent 'event'. * - * @param event - * TreeDragDropEvent triggering 'movePageNode' + * @param dragTreeNode + * TreeNode that is being dragged + * @param dropTreeNode + * TreeNode to which the node is being dropped * @param dropStructureNode * StructureTreeNode containing the Structural Element to which the page is moved * @param dragStructureNode * StructureTreeNode containing the View/Page that is moved */ - private void movePageNode(TreeNode dragTreeNode, TreeNode dropTreeNode, StructureTreeNode dropStructureNode, StructureTreeNode dragStructureNode) throws Exception { + private void movePageNode( + TreeNode dragTreeNode, + TreeNode dropTreeNode, + StructureTreeNode dropStructureNode, + StructureTreeNode dragStructureNode + ) throws Exception { TreeNode dragParent = dragTreeNode.getParent(); if (dragParent.getData() instanceof StructureTreeNode) { StructureTreeNode dragParentTreeNode = (StructureTreeNode) dragParent.getData(); From a0f451c15c1ac712e82c5a20fbfaa696939a3bdd Mon Sep 17 00:00:00 2001 From: Thomas Low Date: Thu, 5 Dec 2024 13:20:17 +0000 Subject: [PATCH 3/4] Fix checkstyle issues in StructurePanel. --- .../kitodo/production/forms/dataeditor/StructurePanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java index 891d74f0903..8cf58272aa2 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java @@ -558,21 +558,21 @@ public void show(boolean keepSelection) { if (!keepSelection) { show(); return; - } + } String physicalRowKey = null; if (Objects.nonNull(selectedPhysicalNode)) { physicalRowKey = selectedPhysicalNode.getRowKey(); } - Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); List keepSelectedLogicalNodes = getSelectedLogicalNodes(); TreeNode keepSelectedPhysicalNode = selectedPhysicalNode; + Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); show(); setSelectedLogicalNodes(keepSelectedLogicalNodes); selectedPhysicalNode = keepSelectedPhysicalNode; restoreSelectionFromRowKeys(logicalRowKeys, this.logicalTree); - + // ------------------------ TODO TODO TODO -------------- /*if (Objects.nonNull(physicalRowKey)) { restoreSelection(physicalRowKey, this.physicalTree); From fa55301df0dd2519dfd0cf847f9a53363f5ccc35 Mon Sep 17 00:00:00 2001 From: Thomas Low Date: Thu, 5 Dec 2024 13:23:51 +0000 Subject: [PATCH 4/4] Fix checkstyle issues in StructurePanel. --- .../org/kitodo/production/forms/dataeditor/StructurePanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java index 8cf58272aa2..9c255e4d562 100644 --- a/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java +++ b/Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/StructurePanel.java @@ -560,6 +560,8 @@ public void show(boolean keepSelection) { return; } + final Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); + String physicalRowKey = null; if (Objects.nonNull(selectedPhysicalNode)) { physicalRowKey = selectedPhysicalNode.getRowKey(); @@ -567,7 +569,6 @@ public void show(boolean keepSelection) { List keepSelectedLogicalNodes = getSelectedLogicalNodes(); TreeNode keepSelectedPhysicalNode = selectedPhysicalNode; - Set logicalRowKeys = getTreeNodeRowKeys(this.getSelectedLogicalNodes()); show(); setSelectedLogicalNodes(keepSelectedLogicalNodes); selectedPhysicalNode = keepSelectedPhysicalNode;