Skip to content

Commit

Permalink
Merge branch 'master' into load-structure-tree-node-label-based-on-ru…
Browse files Browse the repository at this point in the history
…lset-fixes-5882
  • Loading branch information
thomaslow committed Nov 15, 2024
2 parents 89c9383 + 897d524 commit 4026432
Show file tree
Hide file tree
Showing 39 changed files with 2,101 additions and 297 deletions.
4 changes: 4 additions & 0 deletions Kitodo-DataEditor/src/test/resources/ruleset.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,9 @@
if title is selected as the preferred display option.

'title' This field is used as the title to form the author-title key.

'groupDisplayLabel' keys of this type are displayed in the metadata update dialog of the metadata
editor.
</xs:documentation>
</xs:annotation>
<xs:restriction>
Expand All @@ -485,6 +488,7 @@
<xs:enumeration value="processTitle"/>
<xs:enumeration value="recordIdentifier"/>
<xs:enumeration value="structureTreeTitle"/>
<xs:enumeration value="groupDisplayLabel"/>
<xs:enumeration value="title"/>
</xs:restriction>
</xs:simpleType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ public class User extends BaseBean {
@Column(name = "show_physical_page_number_below_thumbnail")
private boolean showPhysicalPageNumberBelowThumbnail;

@ManyToOne
@JoinColumn(name = "default_client_id", foreignKey = @ForeignKey(name = "FK_user_default_client_id"))
private Client defaultClient;

/**
* Constructor for User Entity.
*/
Expand Down Expand Up @@ -160,6 +164,7 @@ public User(User user) {
this.projects = Objects.isNull(user.projects) ? new ArrayList<>() : user.projects;
this.clients = Objects.isNull(user.clients) ? new ArrayList<>() : user.clients;
this.filters = Objects.isNull(user.filters) ? new ArrayList<>() : user.filters;
this.defaultClient = Objects.isNull(user.defaultClient) ? null : user.defaultClient;

if (Objects.nonNull(user.tableSize)) {
this.tableSize = user.tableSize;
Expand Down Expand Up @@ -517,6 +522,24 @@ public void setShowPhysicalPageNumberBelowThumbnail(boolean showPhysicalPageNumb
this.showPhysicalPageNumberBelowThumbnail = showPhysicalPageNumberBelowThumbnail;
}

/**
* Get default client.
*
* @return default client
*/
public Client getDefaultClient() {
return defaultClient;
}

/**
* Set default client.
*
* @param defaultClient default client
*/
public void setDefaultClient(Client defaultClient) {
this.defaultClient = defaultClient;
}

/**
* Removes a user from the environment. Since the
* user ID may still be referenced somewhere, the user is not hard deleted from
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--
-- (c) Kitodo. Key to digital objects e. V. <[email protected]>
--
-- This file is part of the Kitodo project.
--
-- It is licensed under GNU General Public License version 3 or later.
--
-- For the full copyright and license information, please read the
-- GPL3-License.txt file that was distributed with this source code.
--

-- Add column "default_client_id" to "user" table
ALTER TABLE user ADD default_client_id INT;
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ConvertRunner {
/**
* Default timeout.
*/
private static final int DEFAULT_TIMEOUT_MINS = (int) TimeUnit.MINUTES.convert(2, TimeUnit.HOURS);
private static final int DEFAULT_TIMEOUT_SECS = (int) TimeUnit.SECONDS.convert(2, TimeUnit.HOURS);

/**
* {@code convert} command, optionally with full path.
Expand All @@ -72,7 +72,7 @@ void run(IMOperation commandLine) throws IOException {
OutputStream outAndErr = new ByteArrayOutputStream();
executor.setStreamHandler(new PumpStreamHandler(outAndErr));

long timeoutMillis = 1000L * KitodoConfig.getIntParameter(ParameterImageManagement.TIMEOUT_SEC, DEFAULT_TIMEOUT_MINS);
long timeoutMillis = 1000L * KitodoConfig.getIntParameter(ParameterImageManagement.TIMEOUT_SEC, DEFAULT_TIMEOUT_SECS);
executor.setWatchdog(new ExecuteWatchdog(timeoutMillis));

CommandLine command;
Expand Down
18 changes: 6 additions & 12 deletions Kitodo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,6 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
</dependency>
<!-- overwrite parent dependency -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.32</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
Expand Down Expand Up @@ -226,6 +214,12 @@
<artifactId>Saxon-HE</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>${spotbugs-maven-plugin.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>se.jiderhamn.classloader-leak-prevention</groupId>
<artifactId>classloader-leak-prevention-servlet3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,8 @@ public enum ParameterCore implements ParameterInterface {

ACTIVE_MQ_AUTH_PASSWORD(new Parameter<>("activeMQ.authPassword", "")),

ACTIVE_MQ_CREATE_NEW_PROCESSES_QUEUE(new Parameter<UndefinedParameter>("activeMQ.createNewProcesses.queue")),

ACTIVE_MQ_FINALIZE_STEP_QUEUE(new Parameter<UndefinedParameter>("activeMQ.finalizeStep.queue")),

ACTIVE_MQ_KITODO_SCRIPT_ALLOW(new Parameter<UndefinedParameter>("activeMQ.kitodoScript.allow")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ public boolean shouldUserChangeSessionClient() {
* Display client selection dialog if user is logged in and has multiple clients.
*/
public void showClientSelectDialog() {
if (Objects.isNull(getCurrentSessionClient()) && !userHasOnlyOneClient()) {
PrimeFaces.current().executeScript("PF('selectClientDialog').show();");
User currentUser = ServiceManager.getUserService().getCurrentUser();
Client defaultClient = currentUser.getDefaultClient();
if (Objects.nonNull(defaultClient)) {
setSessionClient(defaultClient);
} else if (userHasOnlyOneClient()) {
setSessionClient(getFirstClientOfCurrentUser());
} else if (Objects.isNull(getCurrentSessionClient()) && !userHasOnlyOneClient()) {
PrimeFaces.current().executeScript("PF('selectClientDialog').show();");
}
}

Expand Down Expand Up @@ -162,6 +166,15 @@ public List<Client> getAvailableClientsOfCurrentUser() {
return clients;
}

/**
* Get default client of current user.
*
* @return default client of current user
*/
public Client getDefaultClientOfCurrentUser() {
return ServiceManager.getUserService().getCurrentUser().getDefaultClient();
}

/**
* Get list of available clients of current user sorted by name.
* @return list of available clients of current user sorted by name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ public String deleteFromClient() {
for (Client client : this.userObject.getClients()) {
if (client.getId().equals(clientId)) {
this.userObject.getClients().remove(client);
if (client.equals(this.userObject.getDefaultClient())) {
this.userObject.setDefaultClient(null);
}
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/

package org.kitodo.production.forms.dataeditor;

import java.util.Objects;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

/**
* Bean that is used in externalView.xhtml.
*/
@Named("ExternalView")
@RequestScoped
public class ExternalView {

/**
* Return the shortened ID of the media by removing leading zeros.
*
* @param id the long id of the media file as string
* @return the shortened id of the media file
*/
public static String convertToShortId(String id) {
if (Objects.nonNull(id)) {
return id.replaceFirst("^0+(?!$)", "");
} else {
return "-";
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ private void selectMedia(String physicalDivisionOrder, String stripeIndex, Strin
String scrollScripts = "scrollToSelectedTreeNode();scrollToSelectedPaginationRow();";
if (GalleryViewMode.PREVIEW.equals(galleryViewMode)) {
PrimeFaces.current().executeScript(
"checkScrollPosition();initializeImage();metadataEditor.gallery.mediaView.update();" + scrollScripts);
"checkScrollPosition();metadataEditor.detailMap.update();metadataEditor.gallery.mediaView.update();" + scrollScripts);
} else {
PrimeFaces.current().executeScript(scrollScripts);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,7 @@ private boolean physicalNodeStateUnknown(HashMap<PhysicalDivision, Boolean> expa
}

private LogicalDivision getTreeNodeStructuralElement(TreeNode treeNode) {
if (treeNode.getData() instanceof StructureTreeNode) {
if (Objects.nonNull(treeNode) && treeNode.getData() instanceof StructureTreeNode) {
StructureTreeNode structureTreeNode = (StructureTreeNode) treeNode.getData();
if (structureTreeNode.getDataObject() instanceof LogicalDivision) {
return (LogicalDivision) structureTreeNode.getDataObject();
Expand All @@ -1696,7 +1696,7 @@ private LogicalDivision getTreeNodeStructuralElement(TreeNode treeNode) {
}

private PhysicalDivision getTreeNodePhysicalDivision(TreeNode treeNode) {
if (treeNode.getData() instanceof StructureTreeNode) {
if (Objects.nonNull(treeNode) && treeNode.getData() instanceof StructureTreeNode) {
StructureTreeNode structureTreeNode = (StructureTreeNode) treeNode.getData();
if (structureTreeNode.getDataObject() instanceof PhysicalDivision) {
return (PhysicalDivision) structureTreeNode.getDataObject();
Expand All @@ -1705,6 +1705,16 @@ private PhysicalDivision getTreeNodePhysicalDivision(TreeNode treeNode) {
return null;
}

private View getTreeNodeView(TreeNode treeNode) {
if (Objects.nonNull(treeNode) && treeNode.getData() instanceof StructureTreeNode) {
StructureTreeNode structureTreeNode = (StructureTreeNode) treeNode.getData();
if (structureTreeNode.getDataObject() instanceof View) {
return (View) structureTreeNode.getDataObject();
}
}
return null;
}

/**
* Get List of PhysicalDivisions assigned to multiple LogicalDivisions.
*
Expand Down Expand Up @@ -1767,43 +1777,114 @@ public boolean isAssignedSeveralTimes() {
}

/**
* Check if the selected Node's PhysicalDivision can be assigned to the next logical element in addition to the current assignment.
* Find the next logical structure node that can be used to create a new link to the currently selected node.
* The node needs to be the last node amongst its siblings.
*
* @param node the tree node of the currently selected physical devision node
* @return the next logical tree node
*/
private TreeNode findNextLogicalNodeForViewAssignment(TreeNode node) {
if (Objects.isNull(getTreeNodeView(node))) {
// node is not a view
return null;
}

List<TreeNode> viewSiblings = node.getParent().getChildren();
if (viewSiblings.indexOf(node) != viewSiblings.size() - 1) {
// view is not last view amongst siblings
return null;
}

// pseudo-recursively find next logical node
return findNextLogicalNodeForViewAssignmentRecursive(node.getParent());
}

/**
* Find the next logical structure node that can be used to create a link by pseudo-recursively iterating over
* logical parent and logical children nodes.
*
* @param node the tree node of the logical division
* @return the tree node of the next logical division
*/
private TreeNode findNextLogicalNodeForViewAssignmentRecursive(TreeNode node) {
TreeNode current = node;

while (Objects.nonNull(current)) {
if (Objects.isNull(getTreeNodeStructuralElement(current))) {
// node is not a logical node
return null;
}

// check whether next sibling is a logical node as well
List<TreeNode> currentSiblings = current.getParent().getChildren();
int currentIndex = currentSiblings.indexOf(current);

if (currentSiblings.size() > currentIndex + 1) {
TreeNode nextSibling = currentSiblings.get(currentIndex + 1);
if (Objects.isNull(getTreeNodeStructuralElement(nextSibling))) {
// next sibling is not a logical node
return null;
}

// next sibling is a logical node and potential valid result, unless there are children
TreeNode nextLogical = nextSibling;

// check sibling has children (with first child being another logical node)
while (!nextLogical.getChildren().isEmpty()) {
TreeNode firstChild = nextLogical.getChildren().get(0);
if (Objects.isNull(getTreeNodeStructuralElement(firstChild))) {
// first child is not a logical node
return nextLogical;
}
// iterate to child node
nextLogical = firstChild;
}
return nextLogical;
}

// node is last amongst siblings
// iterate to parent node
current = current.getParent();
}
return null;
}

/**
* Check if the selected Node's PhysicalDivision can be assigned to the next logical element in addition to the
* current assignment.
*
* @return {@code true} if the PhysicalDivision can be assigned to the next LogicalDivision
*/
public boolean isAssignableSeveralTimes() {
if (Objects.nonNull(selectedLogicalNode) && selectedLogicalNode.getData() instanceof StructureTreeNode) {
StructureTreeNode structureTreeNode = (StructureTreeNode) selectedLogicalNode.getData();
if (structureTreeNode.getDataObject() instanceof View) {
List<TreeNode> logicalNodeSiblings = selectedLogicalNode.getParent().getParent().getChildren();
int logicalNodeIndex = logicalNodeSiblings.indexOf(selectedLogicalNode.getParent());
List<TreeNode> viewSiblings = selectedLogicalNode.getParent().getChildren();
// check for selected node's positions and siblings after selected node's parent
if (viewSiblings.indexOf(selectedLogicalNode) == viewSiblings.size() - 1
&& logicalNodeSiblings.size() > logicalNodeIndex + 1) {
TreeNode nextSibling = logicalNodeSiblings.get(logicalNodeIndex + 1);
if (nextSibling.getData() instanceof StructureTreeNode) {
StructureTreeNode structureTreeNodeSibling = (StructureTreeNode) nextSibling.getData();
return structureTreeNodeSibling.getDataObject() instanceof LogicalDivision;
TreeNode nextLogical = findNextLogicalNodeForViewAssignment(selectedLogicalNode);
if (Objects.nonNull(nextLogical)) {
// check whether first child is already view of current node (too avoid adding views multiple times)
if (!nextLogical.getChildren().isEmpty()) {
TreeNode childNode = nextLogical.getChildren().get(0);
View childNodeView = getTreeNodeView(childNode);
View selectedView = getTreeNodeView(selectedLogicalNode);
if (Objects.nonNull(childNodeView) && Objects.nonNull(selectedView)) {
if (childNodeView.equals(selectedView)) {
// first child is already a view for the currently selected node
return false;
}
}
}
return true;
}

return false;
}

/**
* Assign selected Node's PhysicalDivision to the next LogicalDivision.
*/
public void assign() {
if (isAssignableSeveralTimes()) {
TreeNode nextLogical = findNextLogicalNodeForViewAssignment(selectedLogicalNode);
if (Objects.nonNull(nextLogical)) {
View view = (View) ((StructureTreeNode) selectedLogicalNode.getData()).getDataObject();
View viewToAssign = new View();
viewToAssign.setPhysicalDivision(view.getPhysicalDivision());
List<TreeNode> logicalNodeSiblings = selectedLogicalNode.getParent().getParent().getChildren();
int logicalNodeIndex = logicalNodeSiblings.indexOf(selectedLogicalNode.getParent());
TreeNode nextSibling = logicalNodeSiblings.get(logicalNodeIndex + 1);
StructureTreeNode structureTreeNodeSibling = (StructureTreeNode) nextSibling.getData();
StructureTreeNode structureTreeNodeSibling = (StructureTreeNode) nextLogical.getData();
LogicalDivision logicalDivision = (LogicalDivision) structureTreeNodeSibling.getDataObject();
dataEditor.assignView(logicalDivision, viewToAssign, 0);
severalAssignments.add(viewToAssign.getPhysicalDivision());
Expand Down
Loading

0 comments on commit 4026432

Please sign in to comment.