Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import static java.util.Optional.ofNullable;
import static org.sejda.commons.util.RequireUtils.requireNotNullArg;

/**
* Response for a workspace load request
*
* @author Andrea Vacondio
*/
public record LoadWorkspaceResponse(File workspace, Map<String, Map<String, String>> data) {
public LoadWorkspaceResponse(File workspace, Map<String, Map<String, String>> data) {
requireNotNullArg(workspace, "Workspace file cannot be null");
this.workspace = workspace;
this.data = ofNullable(data).orElseGet(HashMap::new);
}

public Map<String, String> getData(String tool) {
return this.data.computeIfAbsent(tool, (k) -> new HashMap<>());
}
public record LoadWorkspaceResponse(WorkspaceData data) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
package org.pdfsam.model.ui.workspace;

import org.pdfsam.model.ui.workspace.WorkspaceData.ToolData;

import java.util.Map;

/**
Expand All @@ -40,5 +42,5 @@ public interface RestorableView {
*
* @param data
*/
void restoreStateFrom(Map<String, String> data);
void restoreStateFrom(ToolData data);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* This file is part of the PDF Split And Merge source code
* Created on 19/08/2025
* Copyright 2025 by Sober Lemur S.r.l. (info@soberlemur.com).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.pdfsam.model.ui.workspace;

import org.pdfsam.model.tool.ToolBound;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static java.util.Optional.ofNullable;
import static org.apache.commons.lang3.StringUtils.EMPTY;

/**
* @author Alessandro Parisi
*/
public class WorkspaceData {
private final File file;
private final Map<String, Map<String, String>> data;
private boolean isRelativePaths = false;

public WorkspaceData(File file, Map<String, Map<String, String>> data) {
this.file = Objects.requireNonNull(file, "Workspace file cannot be null!");
this.data = ofNullable(data).orElseGet(Hashtable::new);

try {
String s = getProperty("relative.paths");
isRelativePaths = Boolean.parseBoolean(s);
} catch (Exception ignored) {
}
}

public String getProperty(String key) {
return ofNullable(data.get(key)).map(Object::toString).orElse(null);
}

public ToolData getToolData(ToolBound tool) {
return new ToolData(isRelativePaths ? file : null, data.get(tool.toolBinding()));
}

public File file() {
return file;
}

public Map<String, Map<String, String>> data() {
return Collections.unmodifiableMap(data);
}

public static class ToolData {
private final File workspaceFile;
private final Map<String, String> data;

public ToolData() {
this(null, new HashMap<>());
}

public ToolData(File workspaceFile, Map<String, String> data) {
this.workspaceFile = workspaceFile;
this.data = Optional.ofNullable(data).orElseGet(HashMap::new);
}

public String get(String key) {
return data.get(key);
}

public String get(String key, String or) {
return ofNullable(data.get(key)).orElse(or);
}

public Integer getInt(String key, Integer or) {
return Optional.ofNullable(get(key)).map(Integer::parseInt).orElse(or);
}

public boolean getBoolean(String key) {
return Optional.ofNullable(get(key)).map(Boolean::parseBoolean).orElse(false);
}

public Path getPath(String key) {
Path toPath = Path.of(get(key, EMPTY));
if (workspaceFile == null || Files.exists(toPath))
return toPath;

try {
Path workspaceDir = workspaceFile.toPath().getParent();
toPath = workspaceDir.resolve(toPath.getFileName());
if (!Files.exists(toPath))
return Path.of("");
return toPath;
} catch (Exception ex) {
return toPath;
}
}

public void set(String key, String value) {
data.put(key, value);
}

public void setBoolean(String key, boolean value) {
data.put(key, Boolean.toString(value));
}

public void setInt(String key, int value) {
data.put(key, Integer.toString(value));
}

public <E extends Enum<E>> void setEnum(String key, E value) {
if (value != null)
set(key, value.toString());
}

public boolean hasKey(String key) {
return data.containsKey(key);
}

public boolean isEmpty() {
return data.isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class LoadWorkspaceResponseTest {
@Test
public void nullDataConstructor() {
File file = mock(File.class);
LoadWorkspaceResponse victim = new LoadWorkspaceResponse(file, null);
assertNotNull(victim.getData("CHUCK"));
assertTrue(victim.getData("CHUCK").isEmpty());
WorkspaceData victim = new WorkspaceData(file, null);
assertNotNull(victim.getToolData(() -> "CHUCK"));
assertTrue(victim.getToolData(() -> "CHUCK").isEmpty());
}

@Test
Expand All @@ -46,8 +46,8 @@ public void withData() {
Map<String, Map<String, String>> moduleData = new HashMap<>();
moduleData.put("module", data);
File file = mock(File.class);
LoadWorkspaceResponse victim = new LoadWorkspaceResponse(file, moduleData);
assertFalse(victim.getData("module").isEmpty());
WorkspaceData victim = new WorkspaceData(file, moduleData);
assertFalse(victim.getToolData(() -> "module").isEmpty());
}

@Test
Expand All @@ -57,8 +57,8 @@ public void getNonExisting() {
Map<String, Map<String, String>> moduleData = new HashMap<>();
moduleData.put("module", data);
File file = mock(File.class);
LoadWorkspaceResponse victim = new LoadWorkspaceResponse(file, moduleData);
assertNotNull(victim.getData("CHUCK"));
assertTrue(victim.getData("CHUCK").isEmpty());
WorkspaceData victim = new WorkspaceData(file, moduleData);
assertNotNull(victim.getToolData(() -> "CHUCK"));
assertTrue(victim.getToolData(() -> "CHUCK").isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.pdfsam.model.ui.workspace.LoadWorkspaceRequest;
import org.pdfsam.model.ui.workspace.LoadWorkspaceResponse;
import org.pdfsam.model.ui.workspace.SaveWorkspaceRequest;
import org.pdfsam.model.ui.workspace.WorkspaceData;
import org.pdfsam.model.ui.workspace.WorkspaceLoadedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -48,6 +49,7 @@ public class WorkspaceController {
private final Collection<Tool> tools;
private final WorkspaceService service;
private final RecentWorkspacesService recentWorkspace;
private WorkspaceData workspace;

@Inject
WorkspaceController(WorkspaceService service, RecentWorkspacesService recentWorkspace) {
Expand Down Expand Up @@ -85,8 +87,9 @@ public void loadWorkspace(LoadWorkspaceRequest event) {
LOG.debug(i18n().tr("Loading workspace from {0}", event.workspace().getName()));
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var data = service.loadWorkspace(event.workspace());
workspace = new WorkspaceData(event.workspace(), data);
if (!data.isEmpty()) {
var response = new LoadWorkspaceResponse(event.workspace(), data);
var response = new LoadWorkspaceResponse(workspace);
tools.forEach(m -> scope.fork(() -> {
eventStudio().broadcast(response, m.id());
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.pdfsam.eventstudio.annotation.EventListener;
import org.pdfsam.eventstudio.annotation.EventStation;
import org.pdfsam.model.tool.ClearToolRequest;
import org.pdfsam.model.ui.workspace.WorkspaceData;
import org.pdfsam.model.ui.workspace.WorkspaceData.ToolData;
import org.pdfsam.ui.components.io.BrowsablePdfOutputField;
import org.pdfsam.ui.components.io.PdfDestinationPane;
import org.pdfsam.ui.components.support.Views;
Expand Down Expand Up @@ -64,20 +66,21 @@ public void onSaveWorkspace(Map<String, String> data) {
}

@Override
public void onLoadWorkspace(Map<String, String> data) {
public void onLoadWorkspace(WorkspaceData workspace) {
ToolData data = workspace.getToolData(this);
// backwards comp when alternate mix had 2 inputs
if (data.containsKey("firstDocumentMixinput")) {
data.put("input.0", data.get("firstDocumentMixinput"));
data.put("input.password.0", data.get("firstDocumentMixinputinput.password"));
data.put("input.step.0", data.get("firstStep"));
data.put("input.reverse.0", data.get("reverseFirst"));
data.put("input.size", "1");
if (data.containsKey("secondDocumentMixinput")) {
data.put("input.1", data.get("secondDocumentMixinput"));
data.put("input.password.1", data.get("secondDocumentMixinput.password"));
data.put("input.step.1", data.get("secondStep"));
data.put("input.reverse.1", data.get("reverseSecond"));
data.put("input.size", "2");
if (data.hasKey("firstDocumentMixinput")) {
data.set("input.0", data.getPath("firstDocumentMixinput").toString());
data.set("input.password.0", data.get("firstDocumentMixinputinput.password"));
data.set("input.step.0", data.get("firstStep"));
data.set("input.reverse.0", data.get("reverseFirst"));
data.setInt("input.size", 1);
if (data.hasKey("secondDocumentMixinput")) {
data.set("input.1", data.getPath("secondDocumentMixinput").toString());
data.set("input.password.1", data.get("secondDocumentMixinput.password"));
data.set("input.step.1", data.get("secondStep"));
data.set("input.reverse.1", data.get("reverseSecond"));
data.setInt("input.size", 2);
}
}
selectionPane.restoreStateFrom(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.pdfsam.core.support.params.TaskParametersBuildStep;
import org.pdfsam.model.ui.ResettableView;
import org.pdfsam.model.ui.workspace.RestorableView;
import org.pdfsam.model.ui.workspace.WorkspaceData.ToolData;
import org.pdfsam.ui.components.commons.ValidableTextField;
import org.pdfsam.ui.components.selection.single.SingleSelectionPane;
import org.pdfsam.ui.components.support.FXValidationSupport;
Expand Down Expand Up @@ -175,7 +176,7 @@ public void saveStateTo(Map<String, String> data) {
}

@Override
public void restoreStateFrom(Map<String, String> data) {
public void restoreStateFrom(ToolData data) {
backpagesSourceField.restoreStateFrom(data);
range.setText(Optional.ofNullable(data.get("range.field")).orElse(EMPTY));
pace.setText(Optional.ofNullable(data.get("pace.field")).orElse(EMPTY));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import org.pdfsam.eventstudio.annotation.EventListener;
import org.pdfsam.eventstudio.annotation.EventStation;
import org.pdfsam.model.tool.ClearToolRequest;
import org.pdfsam.model.ui.workspace.WorkspaceData;
import org.pdfsam.model.ui.workspace.WorkspaceData.ToolData;
import org.pdfsam.ui.components.io.BrowsablePdfOutputField;
import org.pdfsam.ui.components.io.PdfDestinationPane;
import org.pdfsam.ui.components.selection.single.TaskParametersBuilderSingleSelectionPane;
Expand Down Expand Up @@ -72,7 +74,8 @@ public void onSaveWorkspace(Map<String, String> data) {
}

@Override
public void onLoadWorkspace(Map<String, String> data) {
public void onLoadWorkspace(WorkspaceData workspace) {
ToolData data = workspace.getToolData(this);
selectionPane.restoreStateFrom(data);
addBackpagesOptions.restoreStateFrom(data);
destinationFileField.restoreStateFrom(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void start(Stage stage) {
@Test
public void validRange() throws Exception {
populate();
robot.clickOn("#selectedBackpages").type(KeyCode.DIGIT5, KeyCode.MINUS, KeyCode.DIGIT9).push(KeyCode.ENTER);
robot.clickOn("#selectedBackpages").write("5-9").push(KeyCode.ENTER);
victim.apply(builder, onError);
verify(builder).ranges(anySet());
verify(onError, never()).accept(anyString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
import org.pdfsam.core.support.params.TaskParametersBuildStep;
import org.pdfsam.model.ui.ResettableView;
import org.pdfsam.model.ui.workspace.RestorableView;
import org.pdfsam.model.ui.workspace.WorkspaceData.ToolData;
import org.pdfsam.ui.components.commons.ValidableTextField;
import org.pdfsam.ui.components.support.FXValidationSupport.ValidationState;
import org.pdfsam.ui.components.support.Style;
import org.sejda.conversion.exception.ConversionException;

import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

import static org.apache.commons.lang3.StringUtils.EMPTY;
Expand Down Expand Up @@ -112,9 +112,9 @@ public void saveStateTo(Map<String, String> data) {
}

@Override
public void restoreStateFrom(Map<String, String> data) {
field.setText(Optional.ofNullable(data.get("pages")).orElse(EMPTY));
separateFile.setSelected(Boolean.parseBoolean(data.get("separateFile")));
public void restoreStateFrom(ToolData data) {
field.setText(data.get("pages", EMPTY));
separateFile.setSelected(data.getBoolean("separateFile"));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.pdfsam.eventstudio.annotation.EventListener;
import org.pdfsam.eventstudio.annotation.EventStation;
import org.pdfsam.model.tool.ClearToolRequest;
import org.pdfsam.model.ui.workspace.WorkspaceData;
import org.pdfsam.model.ui.workspace.WorkspaceData.ToolData;
import org.pdfsam.ui.components.io.BrowsableOutputDirectoryField;
import org.pdfsam.ui.components.io.PdfDestinationPane;
import org.pdfsam.ui.components.prefix.PrefixPane;
Expand Down Expand Up @@ -85,11 +87,12 @@ public void onSaveWorkspace(Map<String, String> data) {
}

@Override
public void onLoadWorkspace(Map<String, String> data) {
if (data.containsKey("input")) {
data.put("input.0", data.get("input"));
data.put("input.password.0", data.get("input.password"));
data.put("input.size", "1");
public void onLoadWorkspace(WorkspaceData workspace) {
ToolData data = workspace.getToolData(this);
if (data.hasKey("input")) {
data.set("input.0", data.getPath("input").toString());
data.set("input.password.0", data.get("input.password"));
data.setInt("input.size", 1);
}
selectionPane.restoreStateFrom(data);
extractOptions.restoreStateFrom(data);
Expand Down
Loading