From 79e5106d5b4026d88df64624139b0924823a4c6c Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 30 Apr 2020 00:43:03 +0200 Subject: [PATCH] Fixes #6357: File directory Bug was introduced in https://github.com/JabRef/jabref/commit/1b03f039aa4abf0812a3a8ae0ba248c08fdb39a3. --- .../org/jabref/gui/actions/ActionHelper.java | 2 +- .../org/jabref/gui/desktop/JabRefDesktop.java | 15 +-- .../gui/fieldeditors/LinkedFileViewModel.java | 4 +- .../LinkedFilesEditDialogViewModel.java | 2 +- .../gui/preferences/FileTabViewModel.java | 6 +- .../jabref/logic/layout/format/FileLink.java | 3 +- .../layout/format/FileLinkPreferences.java | 11 +- .../logic/layout/format/WrapFileLinks.java | 3 +- .../model/database/BibDatabaseContext.java | 107 +++++++----------- .../org/jabref/model/entry/LinkedFile.java | 2 +- .../org/jabref/model/groups/TexGroup.java | 8 +- .../model/metadata/FilePreferences.java | 30 ++--- .../org/jabref/model/metadata/MetaData.java | 2 +- .../org/jabref/model/util/FileHelper.java | 66 +++-------- .../jabref/preferences/JabRefPreferences.java | 13 +-- .../org/jabref/logic/layout/LayoutTest.java | 4 +- .../layout/format/WrapFileLinksTest.java | 46 ++++---- .../jabref/model/BibDatabaseContextTest.java | 42 ------- .../database/BibDatabaseContextTest.java | 107 +++++++++++++----- 19 files changed, 197 insertions(+), 276 deletions(-) delete mode 100644 src/test/java/org/jabref/model/BibDatabaseContextTest.java diff --git a/src/main/java/org/jabref/gui/actions/ActionHelper.java b/src/main/java/org/jabref/gui/actions/ActionHelper.java index 06f294de5d2..186e3666a5f 100644 --- a/src/main/java/org/jabref/gui/actions/ActionHelper.java +++ b/src/main/java/org/jabref/gui/actions/ActionHelper.java @@ -47,7 +47,7 @@ public static BooleanExpression isFilePresentForSelectedEntry(StateManager state return Bindings.createBooleanBinding(() -> { List files = stateManager.getSelectedEntries().get(0).getFiles(); if ((files.size() > 0) && stateManager.getActiveDatabase().isPresent()) { - Optional filename = FileHelper.expandFilename( + Optional filename = FileHelper.find( stateManager.getActiveDatabase().get(), files.get(0).getLink(), preferencesService.getFilePreferences()); diff --git a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java index 59c0dc0611d..a0fbe80b055 100644 --- a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java @@ -55,12 +55,12 @@ public static void openExternalViewer(BibDatabaseContext databaseContext, String Field field = initialField; if (StandardField.PS.equals(field) || StandardField.PDF.equals(field)) { // Find the default directory for this field type: - List dir = databaseContext.getFileDirectories(field, Globals.prefs.getFilePreferences()); + List directories = databaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFilePreferences()); - Optional file = FileHelper.expandFilename(link, dir); + Optional file = FileHelper.find(link, directories); // Check that the file exists: - if (!file.isPresent() || !Files.exists(file.get())) { + if (file.isEmpty() || !Files.exists(file.get())) { throw new IOException("File not found (" + field + "): '" + link + "'."); } link = file.get().toAbsolutePath().toString(); @@ -126,21 +126,16 @@ public static boolean openExternalFileAnyFormat(final BibDatabaseContext databas return true; } - Optional file = FileHelper.expandFilename(databaseContext, link, Globals.prefs.getFilePreferences()); + Optional file = FileHelper.find(databaseContext, link, Globals.prefs.getFilePreferences()); if (file.isPresent() && Files.exists(file.get())) { // Open the file: String filePath = file.get().toString(); openExternalFilePlatformIndependent(type, filePath); - return true; } else { // No file matched the name, try to open it directly using the given app openExternalFilePlatformIndependent(type, link); - return true; } - } - - public static boolean openExternalFileAnyFormat(Path file, final BibDatabaseContext databaseContext, final Optional type) throws IOException { - return openExternalFileAnyFormat(databaseContext, file.toString(), type); + return true; } private static void openExternalFilePlatformIndependent(Optional fileType, String filePath) diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 62994a86a20..d349f896ebf 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -101,7 +101,7 @@ public LinkedFileViewModel(LinkedFile linkedFile, if (linkedFile.isOnlineLink()) { return true; } else { - Optional path = FileHelper.expandFilename(databaseContext, link, filePreferences); + Optional path = FileHelper.find(databaseContext, link, filePreferences); return path.isPresent() && Files.exists(path.get()); } }, @@ -192,7 +192,7 @@ public void open() { public void openFolder() { try { if (!linkedFile.isOnlineLink()) { - Optional resolvedPath = FileHelper.expandFilename( + Optional resolvedPath = FileHelper.find( databaseContext, linkedFile.getLink(), filePreferences); diff --git a/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java b/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java index 1d2f80b11ff..c3b8dcbd63e 100644 --- a/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java +++ b/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java @@ -70,7 +70,7 @@ private void setExternalFileTypeByExtension(String link) { public void openBrowseDialog() { String fileText = link.get(); - Optional file = FileHelper.expandFilename(database, fileText, preferences.getFilePreferences()); + Optional file = FileHelper.find(database, fileText, preferences.getFilePreferences()); Path workingDir = file.orElse(preferences.getWorkingDir()); String fileName = Paths.get(fileText).getFileName().toString(); diff --git a/src/main/java/org/jabref/gui/preferences/FileTabViewModel.java b/src/main/java/org/jabref/gui/preferences/FileTabViewModel.java index 2346dd22983..f9afdda963c 100644 --- a/src/main/java/org/jabref/gui/preferences/FileTabViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/FileTabViewModel.java @@ -19,8 +19,6 @@ import org.jabref.gui.DialogService; import org.jabref.gui.util.DirectoryDialogConfiguration; import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.field.StandardField; -import org.jabref.model.metadata.FilePreferences; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.NewLineSeparator; @@ -87,7 +85,7 @@ public void setValues() { selectedNewLineSeparatorProperty.setValue(preferences.getNewLineSeparator()); alwaysReformatBibProperty.setValue(preferences.getBoolean(JabRefPreferences.REFORMAT_FILE_ON_SAVE_AND_EXPORT)); - mainFileDirProperty.setValue(preferences.getAsOptional(StandardField.FILE.getName() + FilePreferences.DIR_SUFFIX).orElse("")); + mainFileDirProperty.setValue(preferences.getAsOptional(JabRefPreferences.MAIN_FILE_DIRECTORY).orElse("")); useBibLocationAsPrimaryProperty.setValue(preferences.getBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR)); if (preferences.getBoolean(JabRefPreferences.AUTOLINK_USE_REG_EXP_SEARCH_KEY)) { // Flipped around autolinkUseRegexProperty.setValue(true); @@ -118,7 +116,7 @@ public void storeSettings() { preferences.setNewLineSeparator(selectedNewLineSeparatorProperty.getValue()); preferences.putBoolean(JabRefPreferences.REFORMAT_FILE_ON_SAVE_AND_EXPORT, alwaysReformatBibProperty.getValue()); - preferences.put(StandardField.FILE.getName() + FilePreferences.DIR_SUFFIX, mainFileDirProperty.getValue()); + preferences.put(JabRefPreferences.MAIN_FILE_DIRECTORY, mainFileDirProperty.getValue()); preferences.putBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR, useBibLocationAsPrimaryProperty.getValue()); preferences.putBoolean(JabRefPreferences.AUTOLINK_USE_REG_EXP_SEARCH_KEY, autolinkUseRegexProperty.getValue()); preferences.putBoolean(JabRefPreferences.AUTOLINK_EXACT_KEY_ONLY, autolinkFileExactBibtexProperty.getValue()); diff --git a/src/main/java/org/jabref/logic/layout/format/FileLink.java b/src/main/java/org/jabref/logic/layout/format/FileLink.java index 28aadfaea8b..6045aca1cd0 100644 --- a/src/main/java/org/jabref/logic/layout/format/FileLink.java +++ b/src/main/java/org/jabref/logic/layout/format/FileLink.java @@ -1,6 +1,7 @@ package org.jabref.logic.layout.format; import java.nio.file.Paths; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -55,7 +56,7 @@ public String format(String field) { // ugly hack, the export routine has set a global variable before // starting the export, which contains the database's file directory: if (prefs.getFileDirForDatabase() == null) { - dirs = prefs.getGeneratedDirForDatabase(); + dirs = Collections.singletonList(prefs.getMainFileDirectory()); } else { dirs = prefs.getFileDirForDatabase(); } diff --git a/src/main/java/org/jabref/logic/layout/format/FileLinkPreferences.java b/src/main/java/org/jabref/logic/layout/format/FileLinkPreferences.java index a34e7a6298d..99000174a74 100644 --- a/src/main/java/org/jabref/logic/layout/format/FileLinkPreferences.java +++ b/src/main/java/org/jabref/logic/layout/format/FileLinkPreferences.java @@ -4,15 +4,16 @@ public class FileLinkPreferences { - private final List generatedDirForDatabase; + private final String mainFileDirectory; private final List fileDirForDatabase; - public FileLinkPreferences(List generatedDirForDatabase, List fileDirForDatabase) { - this.generatedDirForDatabase = generatedDirForDatabase; + + public FileLinkPreferences(String mainFileDirectory, List fileDirForDatabase) { + this.mainFileDirectory = mainFileDirectory; this.fileDirForDatabase = fileDirForDatabase; } - public List getGeneratedDirForDatabase() { - return generatedDirForDatabase; + public String getMainFileDirectory() { + return mainFileDirectory; } public List getFileDirForDatabase() { diff --git a/src/main/java/org/jabref/logic/layout/format/WrapFileLinks.java b/src/main/java/org/jabref/logic/layout/format/WrapFileLinks.java index d66e016e3a0..f59d65f3324 100644 --- a/src/main/java/org/jabref/logic/layout/format/WrapFileLinks.java +++ b/src/main/java/org/jabref/logic/layout/format/WrapFileLinks.java @@ -2,6 +2,7 @@ import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -201,7 +202,7 @@ public String format(String field) { // ugly hack, the export routine has set a global variable before // starting the export, which contains the database's file directory: if ((prefs.getFileDirForDatabase() == null) || prefs.getFileDirForDatabase().isEmpty()) { - dirs = prefs.getGeneratedDirForDatabase(); + dirs = Collections.singletonList(prefs.getMainFileDirectory()); } else { dirs = prefs.getFileDirForDatabase(); } diff --git a/src/main/java/org/jabref/model/database/BibDatabaseContext.java b/src/main/java/org/jabref/model/database/BibDatabaseContext.java index 8866cdbbd15..0d8da113042 100644 --- a/src/main/java/org/jabref/model/database/BibDatabaseContext.java +++ b/src/main/java/org/jabref/model/database/BibDatabaseContext.java @@ -1,6 +1,5 @@ package org.jabref.model.database; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -14,8 +13,6 @@ import org.jabref.model.database.shared.DatabaseLocation; import org.jabref.model.database.shared.DatabaseSynchronizer; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; import org.jabref.model.metadata.FilePreferences; import org.jabref.model.metadata.MetaData; @@ -107,63 +104,34 @@ public boolean isBiblatexMode() { return getMode() == BibDatabaseMode.BIBLATEX; } - public List getFileDirectoriesAsPaths(FilePreferences preferences) { - // Filter for empty string, as this would be expanded to the jar-directory with Paths.get() - return getFileDirectories(preferences).stream() - .filter(s -> !s.isEmpty()) - .map(Paths::get) - .map(Path::toAbsolutePath) - .map(Path::normalize) - .collect(Collectors.toList()); - } - /** - * @deprecated use {@link #getFileDirectoriesAsPaths(FilePreferences)} instead - */ - @Deprecated - public List getFileDirectories(FilePreferences preferences) { - return getFileDirectories(StandardField.FILE, preferences); - } - - /** - * Returns the first existing file directory from {@link #getFileDirectories(FilePreferences)} - * - * @param preferences The FilePreferences - * @return Optional of Path - */ - public Optional getFirstExistingFileDir(FilePreferences preferences) { - return getFileDirectoriesAsPaths(preferences).stream().filter(Files::exists).findFirst(); - } - - /** - * Look up the directories set up for the given field type for this database. If no directory is set up, return that - * defined in global preferences. There can be up to three directory definitions for these files: the database's - * metadata can specify a general directory and/or a user-specific directory or the preferences can specify one.

- * The settings are prioritized in the following order and the first defined setting is used: + * Look up the directories set up for this database. + * There can be up to three directory definitions for these files: the database's + * metadata can specify a general directory and/or a user-specific directory, or the preferences can specify one. + *

+ * The settings are prioritized in the following order, and the first defined setting is used: *

    - *
  1. metadata
  2. - *
  3. user-specific directory
  4. + *
  5. user-specific metadata directory
  6. + *
  7. general metadata directory
  8. *
  9. preferences directory
  10. *
  11. BIB file directory
  12. *
* - * @param field The field * @param preferences The fileDirectory preferences - * @return The default directory for this field type. */ - public List getFileDirectories(Field field, FilePreferences preferences) { - List fileDirs = new ArrayList<>(); + public List getFileDirectoriesAsPaths(FilePreferences preferences) { + List fileDirs = new ArrayList<>(); - // 1. metadata user-specific directory + // 1. Metadata user-specific directory metaData.getUserFileDirectory(preferences.getUser()) .ifPresent(userFileDirectory -> fileDirs.add(getFileDirectoryPath(userFileDirectory))); - // 2. metadata general directory + // 2. Metadata general directory metaData.getDefaultFileDirectory() .ifPresent(metaDataDirectory -> fileDirs.add(getFileDirectoryPath(metaDataDirectory))); - // 3. preferences directory - preferences.getFileDirectory(field).ifPresent(path -> fileDirs.add(path.toAbsolutePath().toString())); + // 3. Preferences directory + preferences.getFileDirectory().ifPresent(fileDirs::add); // 4. BIB file directory getDatabasePath().ifPresent(dbPath -> { @@ -173,38 +141,47 @@ public List getFileDirectories(Field field, FilePreferences preferences) parentPath = Paths.get(System.getProperty("user.dir")); } Objects.requireNonNull(parentPath, "BibTeX database parent path is null"); - String parentDir = parentPath.toAbsolutePath().toString(); + // Check if we should add it as primary file dir (first in the list) or not: if (preferences.isBibLocationAsPrimary()) { - fileDirs.add(0, parentDir); + fileDirs.add(0, parentPath); } else { - fileDirs.add(parentDir); + fileDirs.add(parentPath); } }); - return fileDirs; + return fileDirs.stream().map(Path::toAbsolutePath).collect(Collectors.toList()); + } + + /** + * Returns the first existing file directory from {@link #getFileDirectories(FilePreferences)} + * + * @param preferences The FilePreferences + * @return Optional of Path + */ + public Optional getFirstExistingFileDir(FilePreferences preferences) { + return getFileDirectoriesAsPaths(preferences).stream().filter(Files::exists).findFirst(); } - private String getFileDirectoryPath(String directoryName) { - String dir = directoryName; + /** + * @deprecated use {@link #getFileDirectoriesAsPaths(FilePreferences)} instead + */ + @Deprecated + public List getFileDirectories(FilePreferences preferences) { + return getFileDirectoriesAsPaths(preferences).stream() + .map(directory -> directory.toAbsolutePath().toString()) + .collect(Collectors.toList()); + } + + private Path getFileDirectoryPath(String directoryName) { + Path directory = Path.of(directoryName); // If this directory is relative, we try to interpret it as relative to // the file path of this BIB file: Optional databaseFile = getDatabasePath(); - if (!new File(dir).isAbsolute() && databaseFile.isPresent()) { - Path relDir; - if (".".equals(dir)) { - // if dir is only "current" directory, just use its parent (== real current directory) as path - relDir = databaseFile.get().getParent(); - } else { - relDir = databaseFile.get().getParent().resolve(dir); - } - // If this directory actually exists, it is very likely that the - // user wants us to use it: - if (Files.exists(relDir)) { - dir = relDir.toString(); - } + if (!directory.isAbsolute() && databaseFile.isPresent()) { + return databaseFile.get().getParent().resolve(directory).normalize(); } - return dir; + return directory; } public DatabaseSynchronizer getDBMSSynchronizer() { diff --git a/src/main/java/org/jabref/model/entry/LinkedFile.java b/src/main/java/org/jabref/model/entry/LinkedFile.java index dac550e9ded..f06343a6e7a 100644 --- a/src/main/java/org/jabref/model/entry/LinkedFile.java +++ b/src/main/java/org/jabref/model/entry/LinkedFile.java @@ -188,7 +188,7 @@ public Optional findIn(List directories) { return Optional.empty(); } } else { - return FileHelper.expandFilenameAsPath(link.get(), directories); + return FileHelper.find(link.get(), directories); } } catch (InvalidPathException ex) { return Optional.empty(); diff --git a/src/main/java/org/jabref/model/groups/TexGroup.java b/src/main/java/org/jabref/model/groups/TexGroup.java index 9e47568a9e7..883e1d2c48f 100644 --- a/src/main/java/org/jabref/model/groups/TexGroup.java +++ b/src/main/java/org/jabref/model/groups/TexGroup.java @@ -23,12 +23,12 @@ public class TexGroup extends AbstractGroup implements FileUpdateListener { private static final Logger LOGGER = LoggerFactory.getLogger(TexGroup.class); - private Path filePath; + private final Path filePath; private Set keysUsedInAux = null; private final FileUpdateMonitor fileMonitor; - private AuxParser auxParser; + private final AuxParser auxParser; private final MetaData metaData; - private String user; + private final String user; TexGroup(String name, GroupHierarchyType context, Path filePath, AuxParser auxParser, FileUpdateMonitor fileMonitor, MetaData metaData, String user) { super(name, context); @@ -126,7 +126,7 @@ private Path relativize(Path path) { private Path expandPath(Path path) { List fileDirectories = getFileDirectoriesAsPaths(); - return FileHelper.expandFilenameAsPath(path.toString(), fileDirectories).orElse(path); + return FileHelper.find(path.toString(), fileDirectories).orElse(path); } private List getFileDirectoriesAsPaths() { diff --git a/src/main/java/org/jabref/model/metadata/FilePreferences.java b/src/main/java/org/jabref/model/metadata/FilePreferences.java index 52ae33fc63d..efeff249e51 100644 --- a/src/main/java/org/jabref/model/metadata/FilePreferences.java +++ b/src/main/java/org/jabref/model/metadata/FilePreferences.java @@ -1,30 +1,26 @@ package org.jabref.model.metadata; -import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Map; import java.util.Optional; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; +import org.jabref.model.strings.StringUtil; public class FilePreferences { - public static final String DIR_SUFFIX = "Directory"; private final String user; - private final Map fieldFileDirectories; + private final String mainFileDirectory; private final boolean bibLocationAsPrimary; private final String fileNamePattern; private final String fileDirPattern; public FilePreferences(String user, - Map fieldFileDirectories, + String mainFileDirectory, boolean bibLocationAsPrimary, String fileNamePattern, String fileDirPattern) { this.user = user; - this.fieldFileDirectories = fieldFileDirectories; + this.mainFileDirectory = mainFileDirectory; this.bibLocationAsPrimary = bibLocationAsPrimary; this.fileNamePattern = fileNamePattern; this.fileDirPattern = fileDirPattern; @@ -34,24 +30,14 @@ public String getUser() { return user; } - public Optional getFileDirectory(Field field) { - try { - String value = fieldFileDirectories.get(field); - // filter empty paths - if ((value != null) && !value.isEmpty()) { - Path path = Paths.get(value); - return Optional.of(path); - } - return Optional.empty(); - } catch (InvalidPathException ex) { + public Optional getFileDirectory() { + if (StringUtil.isBlank(mainFileDirectory)) { return Optional.empty(); + } else { + return Optional.of(Paths.get(mainFileDirectory)); } } - public Optional getFileDirectory() { - return getFileDirectory(StandardField.FILE); - } - public boolean isBibLocationAsPrimary() { return bibLocationAsPrimary; } diff --git a/src/main/java/org/jabref/model/metadata/MetaData.java b/src/main/java/org/jabref/model/metadata/MetaData.java index a62b70285f4..7a11ec1fe5b 100644 --- a/src/main/java/org/jabref/model/metadata/MetaData.java +++ b/src/main/java/org/jabref/model/metadata/MetaData.java @@ -33,7 +33,7 @@ public class MetaData { public static final String DATABASE_TYPE = "databaseType"; public static final String GROUPSTREE = "grouping"; public static final String GROUPSTREE_LEGACY = "groupstree"; - public static final String FILE_DIRECTORY = "file" + FilePreferences.DIR_SUFFIX; + public static final String FILE_DIRECTORY = "fileDirectory"; public static final String PROTECTED_FLAG_META = "protectedFlag"; public static final String SELECTOR_META_PREFIX = "selector_"; diff --git a/src/main/java/org/jabref/model/util/FileHelper.java b/src/main/java/org/jabref/model/util/FileHelper.java index dba58b1fd21..83a6064ed66 100644 --- a/src/main/java/org/jabref/model/util/FileHelper.java +++ b/src/main/java/org/jabref/model/util/FileHelper.java @@ -6,15 +6,12 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.entry.field.StandardField; import org.jabref.model.metadata.FilePreferences; import org.apache.tika.config.TikaConfig; @@ -88,77 +85,40 @@ private static Optional detectExtension(InputStream is, Metadata metaDat * * * @param databaseContext The database this file belongs to. - * @param name The filename, may also be a relative path to the file + * @param fileName The filename, may also be a relative path to the file */ - public static Optional expandFilename(final BibDatabaseContext databaseContext, String name, FilePreferences filePreferences) { - // Find the default directory for this field type, if any: - List directories = databaseContext.getFileDirectories(StandardField.FILE, filePreferences); - // Include the standard "file" directory: - List fileDir = databaseContext.getFileDirectories(filePreferences); - - List searchDirectories = new ArrayList<>(); - for (String dir : directories) { - if (!searchDirectories.contains(dir)) { - searchDirectories.add(dir); - } - } - for (String aFileDir : fileDir) { - if (!searchDirectories.contains(aFileDir)) { - searchDirectories.add(aFileDir); - } - } - - return expandFilename(name, searchDirectories); + public static Optional find(final BibDatabaseContext databaseContext, String fileName, FilePreferences filePreferences) { + return find(fileName, databaseContext.getFileDirectoriesAsPaths(filePreferences)); } /** * Converts a relative filename to an absolute one, if necessary. Returns - * null if the file does not exist. + * an empty optional if the file does not exist. *

- * Will look in each of the given dirs starting from the beginning and + * Will look in each of the given directories starting from the beginning and * returning the first found file to match if any. - * - * @deprecated use {@link #expandFilenameAsPath(String, List)} instead */ - @Deprecated - public static Optional expandFilename(String name, List directories) { - for (String dir : directories) { - Optional result = expandFilename(name, Paths.get(dir)); - if (result.isPresent()) { - return result; - } - } - - return Optional.empty(); - } - - public static Optional expandFilenameAsPath(String name, List directories) { - for (Path directory : directories) { - Optional result = expandFilename(name, directory); - if (result.isPresent()) { - return result; - } - } - - return Optional.empty(); + public static Optional find(String fileName, List directories) { + return directories.stream() + .flatMap(directory -> find(fileName, directory).stream()) + .findFirst(); } /** * Converts a relative filename to an absolute one, if necessary. Returns * an empty optional if the file does not exist. */ - private static Optional expandFilename(String filename, Path directory) { - Objects.requireNonNull(filename); + public static Optional find(String fileName, Path directory) { + Objects.requireNonNull(fileName); Objects.requireNonNull(directory); - Path file = Paths.get(filename); // Explicitly check for an empty String, as File.exists returns true on that empty path, because it maps to the default jar location // if we then call toAbsoluteDir, it would always return the jar-location folder. This is not what we want here - if (filename.isEmpty()) { + if (fileName.isEmpty()) { return Optional.of(directory); } - Path resolvedFile = directory.resolve(file); + Path resolvedFile = directory.resolve(fileName); if (Files.exists(resolvedFile)) { return Optional.of(resolvedFile); } else { diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index d6fc664ba94..508c533e53f 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -214,6 +214,7 @@ public class JabRefPreferences implements PreferencesService { public static final String USE_DEFAULT_CONSOLE_APPLICATION = "useDefaultConsoleApplication"; public static final String USE_DEFAULT_FILE_BROWSER_APPLICATION = "userDefaultFileBrowserApplication"; public static final String FILE_BROWSER_COMMAND = "fileBrowserCommand"; + public static final String MAIN_FILE_DIRECTORY = "fileDirectory"; // Currently, it is not possible to specify defaults for specific entry types // When this should be made possible, the code to inspect is org.jabref.gui.preferences.BibtexKeyPatternPrefTab.storeSettings() -> LabelPattern keypatterns = getCiteKeyPattern(); etc @@ -1200,12 +1201,10 @@ public void storeFileHistory(FileHistory history) { @Override public FilePreferences getFilePreferences() { - Map fieldDirectories = Stream.of(StandardField.FILE, StandardField.PDF, StandardField.PS) - .collect(Collectors.toMap(field -> field, field -> get(field.getName() + FilePreferences.DIR_SUFFIX, ""))); return new FilePreferences( getUser(), - fieldDirectories, - getBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR), + get(MAIN_FILE_DIRECTORY), + getBoolean(BIB_LOC_AS_PRIMARY_DIR), get(IMPORT_FILENAMEPATTERN), get(IMPORT_FILEDIRPATTERN)); } @@ -1341,10 +1340,10 @@ private NameFormatterPreferences getNameFormatterPreferences() { return new NameFormatterPreferences(getStringList(NAME_FORMATER_KEY), getStringList(NAME_FORMATTER_VALUE)); } - public FileLinkPreferences getFileLinkPreferences() { + private FileLinkPreferences getFileLinkPreferences() { return new FileLinkPreferences( - Collections.singletonList(get(StandardField.FILE.getName() + FilePreferences.DIR_SUFFIX)), - fileDirForDatabase); + get(MAIN_FILE_DIRECTORY), + fileDirForDatabase); } public JabRefPreferences storeVersionPreferences(VersionPreferences versionPreferences) { diff --git a/src/test/java/org/jabref/logic/layout/LayoutTest.java b/src/test/java/org/jabref/logic/layout/LayoutTest.java index 0702a8262cd..415b1573016 100644 --- a/src/test/java/org/jabref/logic/layout/LayoutTest.java +++ b/src/test/java/org/jabref/logic/layout/LayoutTest.java @@ -101,7 +101,7 @@ void HTMLCharsWithDotlessIAndTiled() throws IOException { } @Test - public void beginConditionals() throws IOException { + void beginConditionals() throws IOException { BibEntry entry = new BibEntry(StandardEntryType.Misc) .withField(StandardField.AUTHOR, "Author"); @@ -135,7 +135,7 @@ public void beginConditionals() throws IOException { @Test void wrapFileLinksExpandFile() throws IOException { when(layoutFormatterPreferences.getFileLinkPreferences()).thenReturn( - new FileLinkPreferences(Collections.emptyList(), Collections.singletonList("src/test/resources/pdfs/"))); + new FileLinkPreferences("", Collections.singletonList("src/test/resources/pdfs/"))); BibEntry entry = new BibEntry(StandardEntryType.Article); entry.addFile(new LinkedFile("Test file", "encrypted.pdf", "PDF")); diff --git a/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java b/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java index 09799d584b4..84f5562ced6 100644 --- a/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java +++ b/src/test/java/org/jabref/logic/layout/format/WrapFileLinksTest.java @@ -10,93 +10,93 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class WrapFileLinksTest { +class WrapFileLinksTest { private WrapFileLinks formatter; @BeforeEach - public void setUp() { - FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(), Collections.emptyList()); + void setUp() { + FileLinkPreferences preferences = new FileLinkPreferences("", Collections.emptyList()); formatter = new WrapFileLinks(preferences); } @Test - public void testEmpty() { + void testEmpty() { assertEquals("", formatter.format("")); } @Test - public void testNull() { + void testNull() { assertEquals("", formatter.format(null)); } - public void testNoFormatSetNonEmptyString() { + void testNoFormatSetNonEmptyString() { assertThrows(NullPointerException.class, () -> formatter.format("test.pdf")); } @Test - public void testFileExtension() { + void testFileExtension() { formatter.setArgument("\\x"); assertEquals("pdf", formatter.format("test.pdf")); } @Test - public void testFileExtensionNoExtension() { + void testFileExtensionNoExtension() { formatter.setArgument("\\x"); assertEquals("", formatter.format("test")); } @Test - public void testPlainTextString() { + void testPlainTextString() { formatter.setArgument("x"); assertEquals("x", formatter.format("test.pdf")); } @Test - public void testDescription() { + void testDescription() { formatter.setArgument("\\d"); assertEquals("Test file", formatter.format("Test file:test.pdf:PDF")); } @Test - public void testDescriptionNoDescription() { + void testDescriptionNoDescription() { formatter.setArgument("\\d"); assertEquals("", formatter.format("test.pdf")); } @Test - public void testType() { + void testType() { formatter.setArgument("\\f"); assertEquals("PDF", formatter.format("Test file:test.pdf:PDF")); } @Test - public void testTypeNoType() { + void testTypeNoType() { formatter.setArgument("\\f"); assertEquals("", formatter.format("test.pdf")); } @Test - public void testIterator() { + void testIterator() { formatter.setArgument("\\i"); assertEquals("1", formatter.format("Test file:test.pdf:PDF")); } @Test - public void testIteratorTwoItems() { + void testIteratorTwoItems() { formatter.setArgument("\\i\n"); assertEquals("1\n2\n", formatter.format("Test file:test.pdf:PDF;test2.pdf")); } @Test - public void testEndingBracket() { + void testEndingBracket() { formatter.setArgument("(\\d)"); assertEquals("(Test file)", formatter.format("Test file:test.pdf:PDF")); } @Test - public void testPath() throws IOException { - FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(), + void testPath() throws IOException { + FileLinkPreferences preferences = new FileLinkPreferences("", Collections.singletonList("src/test/resources/pdfs/")); formatter = new WrapFileLinks(preferences); formatter.setArgument("\\p"); @@ -105,8 +105,8 @@ public void testPath() throws IOException { } @Test - public void testPathFallBackToGeneratedDir() throws IOException { - FileLinkPreferences preferences = new FileLinkPreferences(Collections.singletonList("src/test/resources/pdfs/"), + void testPathFallBackToGeneratedDir() throws IOException { + FileLinkPreferences preferences = new FileLinkPreferences("src/test/resources/pdfs/", Collections.emptyList()); formatter = new WrapFileLinks(preferences); formatter.setArgument("\\p"); @@ -115,8 +115,8 @@ public void testPathFallBackToGeneratedDir() throws IOException { } @Test - public void testPathReturnsRelativePathIfNotFound() { - FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(), + void testPathReturnsRelativePathIfNotFound() { + FileLinkPreferences preferences = new FileLinkPreferences("", Collections.singletonList("src/test/resources/pdfs/")); formatter = new WrapFileLinks(preferences); formatter.setArgument("\\p"); @@ -124,7 +124,7 @@ public void testPathReturnsRelativePathIfNotFound() { } @Test - public void testRelativePath() { + void testRelativePath() { formatter.setArgument("\\r"); assertEquals("test.pdf", formatter.format("Test file:test.pdf:PDF")); } diff --git a/src/test/java/org/jabref/model/BibDatabaseContextTest.java b/src/test/java/org/jabref/model/BibDatabaseContextTest.java deleted file mode 100644 index 1be4f0eb7da..00000000000 --- a/src/test/java/org/jabref/model/BibDatabaseContextTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.jabref.model; - -import org.jabref.model.database.BibDatabase; -import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.types.IEEETranEntryType; -import org.jabref.model.metadata.MetaData; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class BibDatabaseContextTest { - @Test - void testTypeBasedOnDefaultBiblatex() { - BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData()); - assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); - - bibDatabaseContext.setMode(BibDatabaseMode.BIBLATEX); - assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); - } - - @Test - void testTypeBasedOnDefaultBibtex() { - BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData()); - assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); - - bibDatabaseContext.setMode(BibDatabaseMode.BIBTEX); - assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode()); - } - - @Test - void testTypeBasedOnInferredModeBiblatex() { - BibDatabase db = new BibDatabase(); - BibEntry e1 = new BibEntry(IEEETranEntryType.Electronic); - db.insertEntry(e1); - - BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(db); - assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); - } -} diff --git a/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java b/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java index 0c60cf2bbc1..449a17f8619 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseContextTest.java @@ -2,11 +2,13 @@ import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.Collections; -import java.util.List; -import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.types.IEEETranEntryType; import org.jabref.model.metadata.FilePreferences; +import org.jabref.model.metadata.MetaData; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -15,61 +17,104 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class BibDatabaseContextTest { +class BibDatabaseContextTest { private Path currentWorkingDir; - // Store the minimal preferences for the - // BibDatabaseContext.getFileDirectories(File, - // FilePreferences) incocation: private FilePreferences fileDirPrefs; @BeforeEach - public void setUp() { + void setUp() { fileDirPrefs = mock(FilePreferences.class); currentWorkingDir = Paths.get(System.getProperty("user.dir")); when(fileDirPrefs.isBibLocationAsPrimary()).thenReturn(true); } @Test - public void getFileDirectoriesWithEmptyDbParent() { - BibDatabaseContext dbContext = new BibDatabaseContext(); - dbContext.setDatabasePath(Paths.get("biblio.bib")); - List fileDirectories = dbContext.getFileDirectories(StandardField.FILE, fileDirPrefs); - assertEquals(Collections.singletonList(currentWorkingDir.toString()), - fileDirectories); + void getFileDirectoriesWithEmptyDbParent() { + BibDatabaseContext database = new BibDatabaseContext(); + database.setDatabasePath(Paths.get("biblio.bib")); + assertEquals(Collections.singletonList(currentWorkingDir), + database.getFileDirectoriesAsPaths(fileDirPrefs)); } @Test - public void getFileDirectoriesWithRelativeDbParent() { + void getFileDirectoriesWithRelativeDbParent() { Path file = Paths.get("relative/subdir").resolve("biblio.bib"); - BibDatabaseContext dbContext = new BibDatabaseContext(); - dbContext.setDatabasePath(file); - List fileDirectories = dbContext.getFileDirectories(StandardField.FILE, fileDirPrefs); - assertEquals(Collections.singletonList(currentWorkingDir.resolve(file.getParent()).toString()), - fileDirectories); + BibDatabaseContext database = new BibDatabaseContext(); + database.setDatabasePath(file); + assertEquals(Collections.singletonList(currentWorkingDir.resolve(file.getParent())), + database.getFileDirectoriesAsPaths(fileDirPrefs)); } @Test - public void getFileDirectoriesWithRelativeDottedDbParent() { + void getFileDirectoriesWithRelativeDottedDbParent() { Path file = Paths.get("./relative/subdir").resolve("biblio.bib"); - BibDatabaseContext dbContext = new BibDatabaseContext(); - dbContext.setDatabasePath(file); - List fileDirectories = dbContext.getFileDirectories(StandardField.FILE, fileDirPrefs); - assertEquals(Collections.singletonList(currentWorkingDir.resolve(file.getParent()).toString()), - fileDirectories); + BibDatabaseContext database = new BibDatabaseContext(); + database.setDatabasePath(file); + assertEquals(Collections.singletonList(currentWorkingDir.resolve(file.getParent())), + database.getFileDirectoriesAsPaths(fileDirPrefs)); } @Test - public void getFileDirectoriesWithAbsoluteDbParent() { + void getFileDirectoriesWithAbsoluteDbParent() { Path file = Paths.get("/absolute/subdir").resolve("biblio.bib"); - BibDatabaseContext dbContext = new BibDatabaseContext(); - dbContext.setDatabasePath(file); - List fileDirectories = dbContext.getFileDirectories(StandardField.FILE, fileDirPrefs); - assertEquals(Collections.singletonList(currentWorkingDir.resolve(file.getParent()).toString()), - fileDirectories); + BibDatabaseContext database = new BibDatabaseContext(); + database.setDatabasePath(file); + assertEquals(Collections.singletonList(currentWorkingDir.resolve(file.getParent())), + database.getFileDirectoriesAsPaths(fileDirPrefs)); + } + + @Test + void getFileDirectoriesWithRelativeMetadata() { + Path file = Paths.get("/absolute/subdir").resolve("biblio.bib"); + + BibDatabaseContext database = new BibDatabaseContext(); + database.setDatabasePath(file); + database.getMetaData().setDefaultFileDirectory("..\\Literature\\"); + assertEquals(Arrays.asList(currentWorkingDir.resolve(file.getParent()), Paths.get("/absolute/Literature").toAbsolutePath()), + database.getFileDirectoriesAsPaths(fileDirPrefs)); + } + + @Test + void getFileDirectoriesWithMetadata() { + Path file = Paths.get("/absolute/subdir").resolve("biblio.bib"); + + BibDatabaseContext database = new BibDatabaseContext(); + database.setDatabasePath(file); + database.getMetaData().setDefaultFileDirectory("Literature\\"); + assertEquals(Arrays.asList(currentWorkingDir.resolve(file.getParent()), Paths.get("/absolute/subdir/Literature").toAbsolutePath()), + database.getFileDirectoriesAsPaths(fileDirPrefs)); + } + + @Test + void testTypeBasedOnDefaultBiblatex() { + BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData()); + assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); + + bibDatabaseContext.setMode(BibDatabaseMode.BIBLATEX); + assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); + } + + @Test + void testTypeBasedOnDefaultBibtex() { + BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData()); + assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); + + bibDatabaseContext.setMode(BibDatabaseMode.BIBTEX); + assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode()); + } + + @Test + void testTypeBasedOnInferredModeBiblatex() { + BibDatabase db = new BibDatabase(); + BibEntry e1 = new BibEntry(IEEETranEntryType.Electronic); + db.insertEntry(e1); + + BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(db); + assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode()); } }