Skip to content

Commit

Permalink
close #532: default working path having precedence over every other. …
Browse files Browse the repository at this point in the history
…If no default working path we then use the input files path as working path. When a relative path is set as output, we resolve against the current working path
  • Loading branch information
torakiki committed Nov 2, 2023
1 parent a62dd12 commit eb8349d
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@
import org.pdfsam.persistence.PreferencesRepository;

import java.io.Closeable;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.Optional;

import static java.util.function.Predicate.not;
import static org.pdfsam.core.context.StringPersistentProperty.FONT_SIZE;
import static org.pdfsam.core.context.StringPersistentProperty.WORKING_PATH;

/**
* @author Andrea Vacondio
Expand Down Expand Up @@ -80,6 +83,16 @@ public ApplicationRuntimeState runtimeState() {
synchronized (this) {
if (Objects.isNull(this.runtimeState)) {
this.runtimeState = new ApplicationRuntimeState();
//listen for changes in the working path
disposable.add(this.persistentSettings().settingsChanges(WORKING_PATH).subscribe(path -> {
this.runtimeState.defaultWorkingPath(
path.filter(StringUtils::isNotBlank).map(Paths::get).filter(Files::isDirectory)
.orElse(null));
}));

var workingPath = persistentSettings().get(WORKING_PATH).filter(StringUtils::isNotBlank).map(Paths::get)
.filter(Files::isDirectory).orElse(null);
this.runtimeState.defaultWorkingPath(workingPath);
}
}
return this.runtimeState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutionException;
Expand All @@ -52,6 +53,7 @@ public class ApplicationRuntimeState implements AutoCloseable {

private static final Logger LOG = LoggerFactory.getLogger(ApplicationRuntimeState.class);

private Path defaultWorkingPath;
private final BehaviorSubject<Optional<Path>> workingPath = BehaviorSubject.createDefault(empty());
private final BehaviorSubject<Optional<Tool>> activeTool = BehaviorSubject.createDefault(empty());
private final ReplaySubject<Theme> theme = ReplaySubject.create(1);
Expand All @@ -64,22 +66,12 @@ public class ApplicationRuntimeState implements AutoCloseable {
}
}

/**
* Sets the current working path for the application
*
* @param path a valid path string. A blank or null or non directory value clears the current working path
*/
public void workingPath(String path) {
this.workingPath(ofNullable(path).filter(StringUtils::isNotBlank).map(Paths::get).orElse(null));

}

/**
* Sets the current working path for the application
*
* @param path the current working directory or the parent in case of regular file. A null value clears the current working path
*/
public void workingPath(Path path) {
void workingPath(Path path) {
workingPath.onNext(ofNullable(path).map(p -> {
if (Files.isRegularFile(p)) {
return p.getParent();
Expand All @@ -88,6 +80,36 @@ public void workingPath(Path path) {
}).filter(Files::isDirectory));
}

/**
* Sets the current working path for the application unless there is a default one already set.
* This method does nothing in case there is a user defined default working path.
*
* @param path a valid path string. A blank or null or non directory value clears the current working path
*/
public void maybeWorkingPath(String path) {
this.maybeWorkingPath(ofNullable(path).filter(StringUtils::isNotBlank).map(Paths::get).orElse(null));
}

/**
* Sets the current working path for the application unless there is a default one already set.
* This method does nothing in case there is a user defined default working path.
*
* @param path the current working directory or the parent in case of regular file. A null value clears the current working path
* @see #workingPath(Path)
*/
public void maybeWorkingPath(Path path) {
if (Objects.isNull(defaultWorkingPath)) {
workingPath(path);
}
}

/**
* @return the current workingPath value
*/
public Optional<Path> workingPathValue() {
return workingPath.getValue();
}

public Observable<Optional<Path>> workingPath() {
return workingPath.hide();
}
Expand Down Expand Up @@ -136,6 +158,11 @@ public void theme(Theme theme) {
ofNullable(theme).ifPresent(this.theme::onNext);
}

void defaultWorkingPath(Path defaultWorkingPath) {
this.defaultWorkingPath = defaultWorkingPath;
workingPath(defaultWorkingPath);
}

@Override
public void close() {
workingPath.onComplete();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public Path showDialog(Window ownerWindow) {
Path selected = ofNullable(wrapped.showDialog(ownerWindow)).map(File::toPath).filter(Files::isDirectory)
.orElse(null);
if (nonNull(selected)) {
app().runtimeState().workingPath(selected);
app().runtimeState().maybeWorkingPath(selected);
}
return selected;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void setFileTypes(FileType... filters) {

private Path updateWorkingPath(Path path) {
if (nonNull(path)) {
app().runtimeState().workingPath(path);
app().runtimeState().maybeWorkingPath(path);
}
return path;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package org.pdfsam.core.context;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.pdfsam.injector.Injector;
import org.pdfsam.persistence.PreferencesRepository;

import java.nio.file.Path;

import static java.util.Optional.empty;
import static java.util.Optional.of;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

Expand All @@ -27,14 +34,28 @@
*/
class ApplicationContextTest {

@Test
void persistentSettings() {
private PreferencesRepository repo;
private ApplicationPersistentSettings persistentSettings;

@BeforeEach
public void setUp() {
repo = mock(PreferencesRepository.class);
persistentSettings = new ApplicationPersistentSettings(repo);
}

@Test
void runtimeStateIsCreated() {
var victim = new ApplicationContext(mock(ApplicationPersistentSettings.class), null);
void runtimeStateIsCreated(@TempDir Path tempDir) {
var victim = new ApplicationContext(persistentSettings, null);
Assertions.assertNotNull(victim.runtimeState());

}

@Test
void runtimeWorkingPathIsBoundToPersistentSetting(@TempDir Path tempDir) {
var victim = new ApplicationContext(persistentSettings, null);
var testListener = victim.runtimeState().workingPath().test();
victim.persistentSettings().set(StringPersistentProperty.WORKING_PATH, tempDir.toString());
testListener.assertValuesOnly(empty(), of(tempDir));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static java.util.Optional.empty;
Expand All @@ -46,57 +48,99 @@ public void setUp() {

@Test
@DisplayName("Existing working Path")
public void positiveWorkingPath(@TempDir Path tempDir) {
public void positiveMaybeWorkingPath(@TempDir Path tempDir) {
var testListener = victim.workingPath().test();
victim.workingPath(tempDir);
victim.maybeWorkingPath(tempDir);
testListener.assertValuesOnly(empty(), of(tempDir));
}

@Test
@DisplayName("Existing working path as String")
public void positiveWorkingPathString(@TempDir Path tempDir) {
public void positiveMaybeWorkingPathString(@TempDir Path tempDir) {
var testListener = victim.workingPath().test();
victim.workingPath(tempDir.toString());
victim.maybeWorkingPath(tempDir.toString());
testListener.assertValuesOnly(empty(), of(tempDir));
}

@Test
@DisplayName("Null working Path")
public void nullWorkingPath(@TempDir Path tempDir) {
public void nullMaybeWorkingPath(@TempDir Path tempDir) {
var testListener = victim.workingPath().test();
victim.workingPath(tempDir);
victim.workingPath((Path) null);
victim.maybeWorkingPath(tempDir);
victim.maybeWorkingPath((Path) null);
testListener.assertValuesOnly(empty(), of(tempDir), empty());
}

@Test
@DisplayName("Null working path as String")
public void nullWorkingPathString(@TempDir Path tempDir) {
public void nullMaybeWorkingPathString(@TempDir Path tempDir) {
var testListener = victim.workingPath().test();
victim.workingPath(tempDir);
victim.workingPath((String) null);
victim.maybeWorkingPath(tempDir);
victim.maybeWorkingPath((String) null);
testListener.assertValuesOnly(empty(), of(tempDir), empty());
}

@Test
@DisplayName("Blank working path as String")
public void blankWorkingPathString(@TempDir Path tempDir) {
public void blankMaybeWorkingPathString(@TempDir Path tempDir) {
var testListener = victim.workingPath().test();
victim.workingPath(tempDir);
victim.workingPath(" ");
victim.maybeWorkingPath(tempDir);
victim.maybeWorkingPath(" ");
testListener.assertValuesOnly(empty(), of(tempDir), empty());
}

@Test
@DisplayName("File working Path")
public void fileWorkingPath(@TempDir Path tempDir) {
public void fileMaybeWorkingPath(@TempDir Path tempDir) throws IOException {
var testListener = victim.workingPath().test();
victim.workingPath(tempDir);
victim.workingPath(tempDir.resolve("test.tmp"));
testListener.assertValuesOnly(empty(), of(tempDir), empty());
victim.maybeWorkingPath(tempDir);
var another = Files.createTempFile(tempDir, "test", ".tmp");
victim.maybeWorkingPath(another);
testListener.assertValuesOnly(empty(), of(tempDir), of(another.getParent()));
}

@Test
@DisplayName("Default working Path")
public void defaultWorkingPath(@TempDir Path tempDir) {
var testListener = victim.workingPath().test();
victim.defaultWorkingPath(tempDir);
testListener.assertValuesOnly(empty(), of(tempDir));
}

@Test
@DisplayName("File working Path with default already set")
public void maybeWorkingPathWithDefault(@TempDir Path tempDir) throws IOException {
var testListener = victim.workingPath().test();
victim.defaultWorkingPath(tempDir);
var another = Files.createTempFile(tempDir, "test", ".tmp");
victim.maybeWorkingPath(another);
testListener.assertValuesOnly(empty(), of(tempDir));
}

@Test
@DisplayName("File working String with default already set")
public void maybeWorkingPathStringWithDefault(@TempDir Path tempDir) throws IOException {
var testListener = victim.workingPath().test();
victim.defaultWorkingPath(tempDir);
var another = Files.createTempFile(tempDir, "test", ".tmp");
victim.maybeWorkingPath(another.toString());
testListener.assertValuesOnly(empty(), of(tempDir));
}

@Test
@DisplayName("Removing default working Path")
public void removeWorkingPathWithDefault(@TempDir Path tempDir) throws IOException {
var testListener = victim.workingPath().test();
victim.defaultWorkingPath(tempDir);
var another = Files.createTempFile(tempDir, "test", ".tmp");
victim.maybeWorkingPath(another);
testListener.assertValuesOnly(empty(), of(tempDir));
testListener.dispose();
var anotherListener = victim.workingPath().test();
victim.defaultWorkingPath(null);
victim.maybeWorkingPath(another);
anotherListener.assertValuesOnly(of(tempDir), empty(), of(another.getParent()));
}

@Test
public void close() {
Expand Down
7 changes: 0 additions & 7 deletions pdfsam-gui/src/main/java/org/pdfsam/gui/PdfsamApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,6 @@ public void init() {
}
app().persistentSettings().get(StringPersistentProperty.LOCALE)
.ifPresent(l -> eventStudio().broadcast(new SetLocaleRequest(l)));
app().runtimeState().workingPath().subscribe(p -> p.ifPresent(path -> {
System.setProperty("user.dir", path.toString());
LOG.debug("user.dir set to '{}'", path);
}));
var workingPath = app().persistentSettings().get(StringPersistentProperty.WORKING_PATH)
.filter(StringUtils::isNotBlank).map(Paths::get).filter(Files::isDirectory).orElse(null);
app().runtimeState().workingPath(workingPath);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ private void doRequestMultiple(FilesDroppedEvent event) {
FileType.TXT.matches(event.files().get(0).getName()) || FileType.CSV.matches(
event.files().get(0).getName()))) {
var path = event.files().get(0).toPath();
app().runtimeState().workingPath(path);
app().runtimeState().maybeWorkingPath(path);
eventStudio().broadcast(new PdfFilesListLoadRequest(event.toolBinding(), path));
} else {
final var loadEvent = new PdfLoadRequest(event.toolBinding());
getFiles(event.files()).filter(f -> FileType.PDF.matches(f.getName()))
.map(PdfDocumentDescriptor::newDescriptorNoPassword).forEach(loadEvent::add);
if (!loadEvent.getDocuments().isEmpty()) {
app().runtimeState().workingPath(loadEvent.getDocuments().get(0).getFileName());
app().runtimeState().maybeWorkingPath(loadEvent.getDocuments().get(0).getFileName());
eventStudio().broadcast(loadEvent, event.toolBinding());
} else {
eventStudio().broadcast(new AddNotificationRequest(NotificationType.WARN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import static java.util.Objects.nonNull;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.pdfsam.core.context.ApplicationContext.app;
import static org.pdfsam.i18n.I18nContext.i18n;

/**
Expand Down Expand Up @@ -67,6 +68,10 @@ public void handle(ActionEvent event) {
String currentSelection = getTextField().getText();
if (isNotBlank(currentSelection)) {
var path = Paths.get(currentSelection);
//if not absolute, resolve against working path
if (!path.isAbsolute()) {
path = app().runtimeState().workingPathValue().map(w -> w.resolve(currentSelection)).orElse(path);
}
if (Files.exists(path)) {
directoryChooser.setInitialDirectory(path);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;

import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim;
import static org.pdfsam.core.context.ApplicationContext.app;
import static org.pdfsam.i18n.I18nContext.i18n;

/**
Expand Down Expand Up @@ -109,7 +109,11 @@ public void handle(ActionEvent event) {
var fileChooser = Choosers.fileChooser(getBrowseWindowTitle(), fileType);
String currentSelection = getTextField().getText();
if (isNotBlank(currentSelection)) {
Path path = Paths.get(currentSelection);
var path = Paths.get(currentSelection);
//if not absolute, resolve against working path
if (!path.isAbsolute()) {
path = app().runtimeState().workingPathValue().map(w -> w.resolve(currentSelection)).orElse(path);
}
if (Files.exists(path)) {
fileChooser.setInitialDirectory(path.getParent());
fileChooser.setInitialFileName(path.getFileName().toString());
Expand Down
Loading

0 comments on commit eb8349d

Please sign in to comment.