Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActionHelper to test for present file #6151

Merged
merged 10 commits into from
Apr 17, 2020
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ private MenuBar createMenu() {

new SeparatorMenuItem(),

factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction()),
factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction(stateManager, prefs)),
factory.createMenuItem(StandardActions.EDIT_ENTRY, new OpenEntryEditorAction(this, stateManager)),
factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OpenConsoleAction(stateManager))
);
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/org/jabref/gui/actions/ActionHelper.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package org.jabref.gui.actions;

import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanExpression;

import org.jabref.gui.StateManager;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.LinkedFile;
import org.jabref.model.entry.field.Field;
import org.jabref.model.entry.field.StandardField;
import org.jabref.model.util.FileHelper;
import org.jabref.preferences.PreferencesService;

public class ActionHelper {
public static BooleanExpression needsDatabase(StateManager stateManager) {
Expand Down Expand Up @@ -36,4 +42,20 @@ public static BooleanExpression isAnyFieldSetForSelectedEntry(List<Field> fields
entry.getFieldsObservable(),
stateManager.getSelectedEntries());
}

public static BooleanExpression isFilePresentForSelectedEntry(StateManager stateManager, PreferencesService preferencesService) {
return Bindings.createBooleanBinding(() -> {
List<LinkedFile> files = stateManager.getSelectedEntries().get(0).getFiles();
if ((files.size() > 0) && stateManager.getActiveDatabase().isPresent()) {
Optional<Path> filename = FileHelper.expandFilename(
stateManager.getActiveDatabase().get(),
files.get(0).getLink(),
preferencesService.getFilePreferences());
return filename.isPresent();
} else {
return false;
}
}, stateManager.getSelectedEntries(),
stateManager.getSelectedEntries().get(0).getFieldBinding(StandardField.FILE));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package org.jabref.gui.documentviewer;

import org.jabref.gui.StateManager;
import org.jabref.gui.actions.ActionHelper;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.preferences.PreferencesService;

public class ShowDocumentViewerAction extends SimpleCommand {

public ShowDocumentViewerAction(StateManager stateManager, PreferencesService preferences) {
this.executable.bind(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferences));
}

@Override
public void execute() {
new DocumentViewerView().show();
}

}
4 changes: 4 additions & 0 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.css
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@
-fx-background-color: -jr-error;
}

.list-cell:invalid {
-fx-background-color: -jr-warn;
}

.code-area .context-menu {
-fx-font-family: sans-serif;
}
Expand Down
54 changes: 35 additions & 19 deletions src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@
import org.jabref.model.entry.LinkedFile;
import org.jabref.model.metadata.FilePreferences;
import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.FileHelper;
import org.jabref.model.util.OptionalUtil;

import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator;
import de.saxsys.mvvmfx.utils.validation.ValidationMessage;
import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
import de.saxsys.mvvmfx.utils.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -69,6 +74,8 @@ public class LinkedFileViewModel extends AbstractViewModel {
private final LinkedFileHandler linkedFileHandler;
private final ExternalFileTypes externalFileTypes;

private final Validator fileExistsValidator;

public LinkedFileViewModel(LinkedFile linkedFile,
BibEntry entry,
BibDatabaseContext databaseContext,
Expand All @@ -88,6 +95,18 @@ public LinkedFileViewModel(LinkedFile linkedFile,
this.externalFileTypes = externalFileTypes;
this.xmpPreferences = xmpPreferences;

fileExistsValidator = new FunctionBasedValidator<>(
linkedFile.linkProperty(),
link -> {
if (linkedFile.isOnlineLink()) {
return true;
} else {
Optional<Path> path = FileHelper.expandFilename(databaseContext, link, filePreferences);
return path.isPresent() && Files.exists(path.get());
}
},
ValidationMessage.warning(Localization.lang("Could not find file '%0'.", linkedFile.getLink())));

downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(1)));
canWriteXMPMetadata.setValue(!linkedFile.isOnlineLink() && linkedFile.getFileType().equalsIgnoreCase("pdf"));
}
Expand Down Expand Up @@ -174,24 +193,19 @@ public void open() {

public void openFolder() {
try {
Path path = null;
// absolute path
if (Paths.get(linkedFile.getLink()).isAbsolute()) {
path = Paths.get(linkedFile.getLink());
} else {
// relative to file folder
for (Path folder : databaseContext.getFileDirectoriesAsPaths(filePreferences)) {
Path file = folder.resolve(linkedFile.getLink());
if (Files.exists(file)) {
path = file;
break;
}
if (!linkedFile.isOnlineLink()) {
Optional<Path> resolvedPath = FileHelper.expandFilename(
databaseContext,
linkedFile.getLink(),
filePreferences);

if (resolvedPath.isPresent()) {
JabRefDesktop.openFolderAndSelectFile(resolvedPath.get());
} else {
dialogService.showErrorDialogAndWait(Localization.lang("File not found"));
}
}
if (path != null) {
JabRefDesktop.openFolderAndSelectFile(path);
} else {
dialogService.showErrorDialogAndWait(Localization.lang("File not found"));
dialogService.showErrorDialogAndWait(Localization.lang("Cannot open folder as the file is an online link."));
}
} catch (IOException ex) {
LOGGER.debug("Cannot open folder", ex);
Expand Down Expand Up @@ -253,7 +267,7 @@ public void moveToDefaultDirectory() {

// Get target folder
Optional<Path> fileDir = databaseContext.getFirstExistingFileDir(filePreferences);
if (!fileDir.isPresent()) {
if (fileDir.isEmpty()) {
dialogService.showErrorDialogAndWait(Localization.lang("Move file"), Localization.lang("File directory is not set or does not exist!"));
return;
}
Expand Down Expand Up @@ -322,7 +336,7 @@ public void moveToDefaultDirectoryAndRename() {
public boolean delete() {
Optional<Path> file = linkedFile.findIn(databaseContext, filePreferences);

if (!file.isPresent()) {
if (file.isEmpty()) {
LOGGER.warn("Could not find file " + linkedFile.getLink());
return true;
}
Expand Down Expand Up @@ -367,7 +381,7 @@ public void writeXMPMetadata() {
// Localization.lang("Writing XMP metadata...")
BackgroundTask<Void> writeTask = BackgroundTask.wrap(() -> {
Optional<Path> file = linkedFile.findIn(databaseContext, filePreferences);
if (!file.isPresent()) {
if (file.isEmpty()) {
// TODO: Print error message
// Localization.lang("PDF does not exist");
} else {
Expand Down Expand Up @@ -457,4 +471,6 @@ private Optional<ExternalFileType> inferFileTypeFromURL(String url) {
public LinkedFile getFile() {
return linkedFile;
}

public ValidationStatus fileExistsValidationStatus() { return fileExistsValidator.getValidationStatus(); }
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ public LinkedFilesEditor(Field field, DialogService dialogService, BibDatabaseCo
.withOnMouseClickedEvent(this::handleItemMouseClick)
.setOnDragDetected(this::handleOnDragDetected)
.setOnDragDropped(this::handleOnDragDropped)
.setOnDragOver(this::handleOnDragOver);
.setOnDragOver(this::handleOnDragOver)
.withValidation(LinkedFileViewModel::fileExistsValidationStatus);

listView.setCellFactory(cellFactory);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.jabref.gui.fieldeditors.LinkedFileViewModel;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.StandardField;
import org.jabref.preferences.PreferencesService;

public class OpenExternalFileAction extends SimpleCommand {
Expand All @@ -25,7 +24,7 @@ public OpenExternalFileAction(DialogService dialogService, StateManager stateMan
this.stateManager = stateManager;
this.preferencesService = preferencesService;

this.executable.bind(ActionHelper.isFieldSetForSelectedEntry(StandardField.FILE, stateManager)
this.executable.bind(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferencesService)
.and(ActionHelper.needsEntriesSelected(1, stateManager)));
}

Expand Down
3 changes: 1 addition & 2 deletions src/main/java/org/jabref/gui/maintable/OpenFolderAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.fieldeditors.LinkedFileViewModel;
import org.jabref.model.entry.field.StandardField;
import org.jabref.preferences.PreferencesService;

public class OpenFolderAction extends SimpleCommand {
Expand All @@ -21,7 +20,7 @@ public OpenFolderAction(DialogService dialogService, StateManager stateManager,
this.stateManager = stateManager;
this.preferencesService = preferencesService;

this.executable.bind(ActionHelper.isFieldSetForSelectedEntry(StandardField.FILE, stateManager));
this.executable.bind(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferencesService));
}

@Override
Expand Down
22 changes: 17 additions & 5 deletions src/main/java/org/jabref/gui/util/ViewModelListCellFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.jabref.gui.icon.JabRefIcon;
import org.jabref.model.strings.StringUtil;

import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
import org.fxmisc.easybind.Subscription;

/**
Expand All @@ -31,6 +32,8 @@
*/
public class ViewModelListCellFactory<T> implements Callback<ListView<T>, ListCell<T>> {

private static final PseudoClass INVALID_PSEUDO_CLASS = PseudoClass.getPseudoClass("invalid");

private Callback<T, String> toText;
private Callback<T, Node> toGraphic;
private Callback<T, Tooltip> toTooltip;
Expand All @@ -43,6 +46,7 @@ public class ViewModelListCellFactory<T> implements Callback<ListView<T>, ListCe
private BiConsumer<T, ? super DragEvent> toOnDragExited;
private BiConsumer<T, ? super DragEvent> toOnDragOver;
private Map<PseudoClass, Callback<T, ObservableValue<Boolean>>> pseudoClasses = new HashMap<>();
private Callback<T, ValidationStatus> validationStatusProperty;

public ViewModelListCellFactory<T> withText(Callback<T, String> toText) {
this.toText = toText;
Expand All @@ -66,10 +70,7 @@ public ViewModelListCellFactory<T> withIcon(Callback<T, JabRefIcon> toIcon) {
}

public ViewModelListCellFactory<T> withIcon(Callback<T, JabRefIcon> toIcon, Callback<T, Color> toColor) {
this.toGraphic = viewModel -> {

return toIcon.call(viewModel).withColor(toColor.call(viewModel)).getGraphicNode();
};
this.toGraphic = viewModel -> toIcon.call(viewModel).withColor(toColor.call(viewModel)).getGraphicNode();
return this;
}

Expand Down Expand Up @@ -134,6 +135,11 @@ public ViewModelListCellFactory<T> withPseudoClass(PseudoClass pseudoClass, Call
return this;
}

public ViewModelListCellFactory<T> withValidation(Callback<T, ValidationStatus> validationStatusProperty) {
this.validationStatusProperty = validationStatusProperty;
return this;
}

public void install(ComboBox<T> comboBox) {
comboBox.setButtonCell(this.call(null));
comboBox.setCellFactory(this);
Expand All @@ -146,7 +152,7 @@ public void install(ListView<T> listView) {
@Override
public ListCell<T> call(ListView<T> param) {

return new ListCell<T>() {
return new ListCell<>() {

List<Subscription> subscriptions = new ArrayList<>();

Expand Down Expand Up @@ -203,6 +209,12 @@ protected void updateItem(T item, boolean empty) {
Subscription subscription = BindingsHelper.includePseudoClassWhen(this, pseudoClassWithCondition.getKey(), condition);
subscriptions.add(subscription);
}
if (validationStatusProperty != null) {
validationStatusProperty.call(viewModel).getHighestMessage().ifPresent(message -> {
setTooltip(new Tooltip(message.getMessage()));
subscriptions.add(BindingsHelper.includePseudoClassWhen(this, INVALID_PSEUDO_CLASS, validationStatusProperty.call(viewModel).validProperty().not()));
});
}
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/model/entry/BibEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ public Optional<FieldChange> setFiles(List<LinkedFile> files) {
public List<LinkedFile> getFiles() {
// Extract the path
Optional<String> oldValue = getField(StandardField.FILE);
if (!oldValue.isPresent()) {
if (oldValue.isEmpty()) {
return new ArrayList<>(); // Return new ArrayList because emptyList is immutable
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ Cannot\ create\ group=Cannot create group

Cannot\ create\ group.\ Please\ create\ a\ library\ first.=Cannot create group. Please create a library first.

Cannot\ open\ folder\ as\ the\ file\ is\ an\ online\ link.=Cannot open folder as the file is an online link.

case\ insensitive=case insensitive

case\ sensitive=case sensitive
Expand Down