Skip to content

Commit 30816f2

Browse files
authored
Merge pull request #6340 from thomaslow/move-multiple-pages-in-structure-tree-fixes-5926
Drag & drop multiple tree nodes in structure tree
2 parents bc9c3d0 + 5a0c7ea commit 30816f2

21 files changed

Lines changed: 1474 additions & 675 deletions

Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/AddDocStrucTypeDialog.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,13 @@ private void addSingleDocStruc(boolean selectViews) {
182182
}
183183
}
184184
dataEditor.refreshStructurePanel();
185-
TreeNode selectedLogicalTreeNode = dataEditor.getStructurePanel().updateLogicalNodeSelectionRecursive(newStructure,
186-
this.dataEditor.getStructurePanel().getLogicalTree());
187-
if (Objects.nonNull(selectedLogicalTreeNode)) {
188-
this.dataEditor.getStructurePanel().setSelectedLogicalNode(selectedLogicalTreeNode);
189-
this.dataEditor.getMetadataPanel().showLogical(this.dataEditor.getSelectedStructure());
190-
dataEditor.refreshStructurePanel();
185+
186+
try {
187+
dataEditor.updateSelection(Collections.emptyList(), Collections.singletonList(newStructure));
188+
} catch (NoSuchMetadataFieldException e) {
189+
Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
191190
}
191+
192192
List<Pair<PhysicalDivision, LogicalDivision>> selectedMedia = this.dataEditor.getSelectedMedia().stream()
193193
.sorted(Comparator.comparingInt(p -> p.getLeft().getOrder()))
194194
.collect(Collectors.toList());
@@ -434,15 +434,35 @@ public void prepare() {
434434
}
435435
}
436436

437+
/**
438+
* Determines the logical parent division that can be used as a basis for the dialog and overwrites the
439+
* user selection with this logical parent division.
440+
*
441+
* <p>Note: Sneakily overwriting the current user selection is a very bad legacy design choice of this dialog.
442+
* This should be improved in the future!</p>
443+
*/
437444
private void checkSelectedLogicalNode() {
438-
//If a view is selected in logical tree then the 'selectedLogicalNode' will be set to the parent of this view
439-
TreeNode selectedLogicalNode = dataEditor.getStructurePanel().getSelectedLogicalNode();
440-
if (Objects.nonNull(selectedLogicalNode) && selectedLogicalNode.getData() instanceof StructureTreeNode) {
441-
StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData();
442-
if (structureTreeNode.getDataObject() instanceof View) {
443-
if (Objects.nonNull(selectedLogicalNode.getParent())) {
444-
previouslySelectedLogicalNode = selectedLogicalNode;
445-
dataEditor.getStructurePanel().setSelectedLogicalNode(selectedLogicalNode.getParent());
445+
Set<LogicalDivision> logicalDivisionSet = dataEditor.getStructurePanel().getSelectedLogicalNodes().stream()
446+
.map(StructureTreeOperations::getTreeNodeLogicalParentOrSelf)
447+
.map(StructureTreeOperations::getLogicalDivisionFromTreeNode)
448+
.collect(Collectors.toSet());
449+
450+
if (logicalDivisionSet.isEmpty()) {
451+
// determine logical parent division for selection of media (in case of gallery selection)
452+
logicalDivisionSet.addAll(
453+
dataEditor.getSelectedMedia().stream()
454+
.map(Pair::getRight)
455+
.collect(Collectors.toSet())
456+
);
457+
}
458+
459+
if (logicalDivisionSet.size() == 1) {
460+
LogicalDivision logicalDivision = logicalDivisionSet.iterator().next();
461+
if (Objects.nonNull(logicalDivision)) {
462+
try {
463+
dataEditor.updateSelection(Collections.emptyList(), Collections.singletonList(logicalDivision));
464+
} catch (NoSuchMetadataFieldException e) {
465+
Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
446466
}
447467
}
448468
}
@@ -594,7 +614,7 @@ public void resetValues() {
594614
selectFirstPageOnAddNode = null;
595615
selectLastPageOnAddNode = null;
596616
if (Objects.nonNull(previouslySelectedLogicalNode)) {
597-
dataEditor.getStructurePanel().setSelectedLogicalNode(previouslySelectedLogicalNode);
617+
dataEditor.getStructurePanel().setSelectedLogicalNodes(Collections.singletonList(previouslySelectedLogicalNode));
598618
previouslySelectedLogicalNode = null;
599619
}
600620
}
@@ -727,13 +747,13 @@ public String getCurrentStructureLabel() {
727747
return " - ";
728748
}
729749
}
730-
750+
731751
private StructuralElementViewInterface getDivisionViewOfStructure(String structure) {
732752
StructuralElementViewInterface divisionView = dataEditor.getRulesetManagement()
733753
.getStructuralElementView(structure, dataEditor.getAcquisitionStage(), dataEditor.getPriorityList());
734754
return divisionView;
735755
}
736-
756+
737757
/**
738758
* This method checks if the selected metadatakey refers to complex metadata.
739759
*

Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/AddPhysicalDivisionDialog.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package org.kitodo.production.forms.dataeditor;
1313

1414
import java.util.ArrayList;
15+
import java.util.Arrays;
1516
import java.util.Collections;
1617
import java.util.LinkedList;
1718
import java.util.List;
@@ -21,6 +22,7 @@
2122

2223
import javax.faces.model.SelectItem;
2324

25+
import org.apache.commons.lang3.tuple.ImmutablePair;
2426
import org.kitodo.api.dataeditor.rulesetmanagement.StructuralElementViewInterface;
2527
import org.kitodo.api.dataformat.PhysicalDivision;
2628
import org.kitodo.production.helper.Helper;
@@ -53,7 +55,10 @@ public void addPhysicalDivision() {
5355
selectedPhysicalDivision.get(),
5456
selectedPosition);
5557
dataEditor.refreshStructurePanel();
56-
dataEditor.getStructurePanel().selectPhysicalDivision(physicalDivision);
58+
dataEditor.getStructurePanel().updateNodeSelection(
59+
List.of(new ImmutablePair<>(physicalDivision, null)),
60+
Collections.emptyList()
61+
);
5762
} else {
5863
Helper.setErrorMessage("No physical division selected!");
5964
}

Kitodo/src/main/java/org/kitodo/production/forms/dataeditor/DataEditorForm.java

Lines changed: 64 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.nio.file.Paths;
2323
import java.util.ArrayList;
2424
import java.util.Collection;
25+
import java.util.Collections;
2526
import java.util.HashSet;
2627
import java.util.LinkedList;
2728
import java.util.List;
@@ -419,16 +420,14 @@ private void init() {
419420
structurePanel.getSeveralAssignments().addAll(severalAssignments);
420421

421422
structurePanel.show();
422-
structurePanel.getSelectedLogicalNode().setSelected(true);
423-
structurePanel.getSelectedPhysicalNode().setSelected(true);
424423
metadataPanel.showLogical(getSelectedStructure());
425424
metadataPanel.showPhysical(getSelectedPhysicalDivision());
426425
galleryPanel.setGalleryViewMode(GalleryViewMode.getByName(user.getDefaultGalleryViewMode()).name());
427426
galleryPanel.show();
428427
paginationPanel.show();
429-
430428
editPagesDialog.prepare();
431429
updateNumberOfScans();
430+
updateToDefaultSelection();
432431

433432
if (logger.isTraceEnabled()) {
434433
logger.trace("Initializing editor beans took {} ms",
@@ -633,7 +632,7 @@ public void deleteStructure() {
633632
* clicked on the context menu entry to delete the physical division.
634633
*/
635634
public void deletePhysicalDivision() {
636-
structurePanel.deleteSelectedPhysicalDivision();
635+
structurePanel.deleteSelectedPhysicalDivisions();
637636
updateNumberOfScans();
638637
}
639638

@@ -876,94 +875,80 @@ public boolean isSelected(PhysicalDivision physicalDivision, LogicalDivision log
876875
return false;
877876
}
878877

879-
void switchStructure(Object treeNodeData, boolean updateGalleryAndPhysicalTree) throws NoSuchMetadataFieldException {
878+
/**
879+
* Select first logical division when opening data editor.
880+
*/
881+
public void updateToDefaultSelection() {
882+
TreeNode firstSelectedLogicalNode = getStructurePanel().getLogicalTree().getChildren().get(
883+
getStructurePanel().getLogicalTree().getChildCount() - 1
884+
);
880885
try {
881-
metadataPanel.preserveLogical();
882-
} catch (InvalidMetadataValueException e) {
883-
logger.info(e.getLocalizedMessage(), e);
884-
}
885-
886-
Optional<LogicalDivision> selectedStructure = structurePanel.getSelectedStructure();
887-
888-
metadataPanel.showLogical(selectedStructure);
889-
if (treeNodeData instanceof StructureTreeNode) {
890-
StructureTreeNode structureTreeNode = (StructureTreeNode) treeNodeData;
891-
if (Objects.nonNull(structureTreeNode.getDataObject())) {
892-
if (structureTreeNode.getDataObject() instanceof LogicalDivision
893-
&& selectedStructure.isPresent()) {
894-
// Logical structure element selected
895-
if (structurePanel.isSeparateMedia()) {
896-
LogicalDivision structuralElement = selectedStructure.get();
897-
if (!structuralElement.getViews().isEmpty()) {
898-
ArrayList<View> views = new ArrayList<>(structuralElement.getViews());
899-
if (Objects.nonNull(views.get(0)) && updateGalleryAndPhysicalTree) {
900-
updatePhysicalStructureTree(views.get(0));
901-
updateGallery(views.get(0));
902-
}
903-
} else {
904-
updatePhysicalStructureTree(null);
905-
}
906-
} else {
907-
getSelectedMedia().clear();
908-
}
909-
} else if (structureTreeNode.getDataObject() instanceof View) {
910-
View view = (View) structureTreeNode.getDataObject();
911-
if (view.getPhysicalDivision().hasMediaPartial()) {
912-
View mediaView = DataEditorService.getViewOfBaseMediaByMediaFiles(structurePanel.getLogicalTree().getChildren(),
913-
view.getPhysicalDivision().getMediaFiles());
914-
if (Objects.nonNull(mediaView)) {
915-
view = mediaView;
916-
}
917-
}
918-
919-
metadataPanel.showPageInLogical(view.getPhysicalDivision());
920-
if (updateGalleryAndPhysicalTree) {
921-
updateGallery(view);
922-
}
923-
// no need to update physical tree because pages can only be clicked in logical tree if physical tree is hidden!
924-
}
925-
}
886+
updateSelection(
887+
Collections.emptyList(),
888+
Collections.singletonList(StructureTreeOperations.getLogicalDivisionFromTreeNode(firstSelectedLogicalNode))
889+
);
890+
} catch (NoSuchMetadataFieldException e) {
891+
logger.error("exception updating to default selection", e);
926892
}
927-
paginationPanel.preparePaginationSelectionSelectedItems();
928893
}
929894

930-
931-
932-
void switchPhysicalDivision() throws NoSuchMetadataFieldException {
895+
/**
896+
* Update the current selection in the metadata editor by dispatching update events to structure trees,
897+
* gallery and pagination panel.
898+
*
899+
* @param selectedPhysicalDivisions the list of selected physical divisions (and their parent logical divisions)
900+
* @param selectedLogicalDivisions the list of selected logical divisions
901+
* @throws NoSuchMetadataFieldException exception in case metadata can not be saved correctly
902+
*/
903+
public void updateSelection(
904+
List<Pair<PhysicalDivision, LogicalDivision>> selectedPhysicalDivisions,
905+
List<LogicalDivision> selectedLogicalDivisions
906+
) throws NoSuchMetadataFieldException {
933907
try {
934-
metadataPanel.preservePhysical();
908+
// save previously edited meta data
909+
getMetadataPanel().preserveLogical();
935910
} catch (InvalidMetadataValueException e) {
936911
logger.info(e.getLocalizedMessage(), e);
937912
}
938913

939-
Optional<PhysicalDivision> selectedPhysicalDivision = structurePanel.getSelectedPhysicalDivision();
940-
941-
metadataPanel.showPhysical(selectedPhysicalDivision);
942-
if (selectedPhysicalDivision.isPresent()) {
943-
// update gallery
944-
galleryPanel.updateSelection(selectedPhysicalDivision.get(), null);
945-
// update logical tree
946-
for (GalleryMediaContent galleryMediaContent : galleryPanel.getMedias()) {
947-
if (Objects.nonNull(galleryMediaContent.getView())
948-
&& Objects.equals(selectedPhysicalDivision.get(), galleryMediaContent.getView().getPhysicalDivision())) {
949-
structurePanel.updateLogicalNodeSelection(galleryMediaContent, null);
950-
break;
951-
}
914+
// update data editor selection (used e.g. in gallery)
915+
getSelectedMedia().clear();
916+
getSelectedMedia().addAll(selectedPhysicalDivisions);
917+
918+
// update logical metadata panel
919+
if (!getStructurePanel().isSeparateMedia() && selectedPhysicalDivisions.size() == 1
920+
&& selectedLogicalDivisions.isEmpty()) {
921+
// show physical division in logical metadata panel in combined meta data mode
922+
getMetadataPanel().showPageInLogical(selectedPhysicalDivisions.get(0).getLeft());
923+
} else if (selectedLogicalDivisions.size() == 1 && selectedPhysicalDivisions.isEmpty()) {
924+
// show logical division in logical metadata panel
925+
getMetadataPanel().showLogical(Optional.of(selectedLogicalDivisions.get(0)));
926+
} else {
927+
// show nothing in logical metadata panel
928+
getMetadataPanel().showPageInLogical(null);
929+
}
930+
931+
// update physical metadata panel
932+
if (getStructurePanel().isSeparateMedia()) {
933+
if (selectedPhysicalDivisions.size() == 1) {
934+
// show physical division in physical metadata panel
935+
getMetadataPanel().showPhysical(Optional.of(selectedPhysicalDivisions.get(0).getLeft()));
936+
} else {
937+
// show nothing in physical metadata panel
938+
getMetadataPanel().showPhysical(Optional.empty());
952939
}
953940
}
954-
}
955941

956-
private void updatePhysicalStructureTree(View view) {
957-
GalleryMediaContent galleryMediaContent = this.galleryPanel.getGalleryMediaContent(view);
958-
structurePanel.updatePhysicalNodeSelection(galleryMediaContent);
942+
// update structure trees
943+
getStructurePanel().updateNodeSelection(
944+
selectedPhysicalDivisions,
945+
selectedLogicalDivisions
946+
);
947+
948+
// update pagination panel
949+
getPaginationPanel().preparePaginationSelectionSelectedItems();
959950
}
960951

961-
private void updateGallery(View view) {
962-
PhysicalDivision physicalDivision = view.getPhysicalDivision();
963-
if (Objects.nonNull(physicalDivision)) {
964-
galleryPanel.updateSelection(physicalDivision, structurePanel.getPageStructure(view, workpiece.getLogicalStructure()));
965-
}
966-
}
967952

968953
void assignView(LogicalDivision logicalDivision, View view, Integer index) {
969954
if (Objects.nonNull(index) && index >= 0 && index < logicalDivision.getViews().size()) {
@@ -1317,7 +1302,7 @@ public String getMetadataFileLoadingError() {
13171302
*/
13181303
public boolean canUpdateMetadata() {
13191304
try {
1320-
return DataEditorService.canUpdateCatalogMetadata(process, workpiece, structurePanel.getSelectedLogicalNode());
1305+
return DataEditorService.canUpdateCatalogMetadata(process, workpiece, structurePanel.getSelectedLogicalNodeIfSingle());
13211306
} catch (IOException e) {
13221307
Helper.setErrorMessage(e.getLocalizedMessage(), logger, e);
13231308
return false;

0 commit comments

Comments
 (0)