diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 804b7155253..3e2656a6d5c 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -136,6 +136,7 @@ import org.jabref.model.entry.event.EntryEventSource; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.model.entry.specialfields.SpecialFieldValue; +import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreviewPreferences; import org.jabref.shared.DBMSSynchronizer; @@ -522,11 +523,11 @@ public void update() { actions.put(Actions.OPEN_EXTERNAL_FILE, (BaseAction) () -> openExternalFile()); actions.put(Actions.OPEN_FOLDER, (BaseAction) () -> JabRefExecutorService.INSTANCE.execute(() -> { - final List files = FileUtil.getListOfLinkedFiles(mainTable.getSelectedEntries(), + final List files = FileUtil.getListOfLinkedFiles(mainTable.getSelectedEntries(), bibDatabaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences())); - for (final File f : files) { + for (final Path f : files) { try { - JabRefDesktop.openFolderAndSelectFile(f.getAbsolutePath()); + JabRefDesktop.openFolderAndSelectFile(f.toAbsolutePath()); } catch (IOException e) { LOGGER.info("Could not open folder", e); } @@ -2119,7 +2120,7 @@ public Optional searchAndOpen() { final List res = result.get(entry); if (!res.isEmpty()) { final String filepath = res.get(0).getPath(); - final Optional extension = FileUtil.getFileExtension(filepath); + final Optional extension = FileHelper.getFileExtension(filepath); if (extension.isPresent()) { Optional type = ExternalFileTypes.getInstance() .getExternalFileTypeByExt(extension.get()); diff --git a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java index d41224bb357..7b3c86c7382 100644 --- a/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/JabRefDesktop.java @@ -2,6 +2,9 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -31,12 +34,12 @@ import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.OS; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.identifier.DOI; import org.jabref.model.entry.identifier.Eprint; +import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; import org.apache.commons.logging.Log; @@ -66,16 +69,16 @@ public static void openExternalViewer(BibDatabaseContext databaseContext, String // Find the default directory for this field type: List dir = databaseContext.getFileDirectories(fieldName, Globals.prefs.getFileDirectoryPreferences()); - Optional file = FileUtil.expandFilename(link, dir); + Optional file = FileHelper.expandFilename(link, dir); // Check that the file exists: - if (!file.isPresent() || !file.get().exists()) { + if (!file.isPresent() || !Files.exists(file.get())) { throw new IOException("File not found (" + fieldName + "): '" + link + "'."); } - link = file.get().getCanonicalPath(); + link = file.get().toAbsolutePath().toString(); // Use the correct viewer even if pdf and ps are mixed up: - String[] split = file.get().getName().split("\\."); + String[] split = file.get().getFileName().toString().split("\\."); if (split.length >= 2) { if ("pdf".equalsIgnoreCase(split[split.length - 1])) { fieldName = FieldName.PDF; @@ -138,10 +141,9 @@ public static boolean openExternalFileAnyFormat(final BibDatabaseContext databas } // For other platforms we'll try to find the file type: - File file = new File(link); - + Path file = Paths.get(link); if (!httpLink) { - Optional tmp = FileUtil.expandFilename(databaseContext, link, + Optional tmp = FileHelper.expandFilename(databaseContext, link, Globals.prefs.getFileDirectoryPreferences()); if (tmp.isPresent()) { file = tmp.get(); @@ -149,9 +151,9 @@ public static boolean openExternalFileAnyFormat(final BibDatabaseContext databas } // Check if we have arrived at a file type, and either an http link or an existing file: - if ((httpLink || file.exists()) && (type.isPresent())) { + if (httpLink || Files.exists(file) && (type.isPresent())) { // Open the file: - String filePath = httpLink ? link : file.getPath(); + String filePath = httpLink ? link : file.toString(); openExternalFilePlatformIndependent(type, filePath); return true; } else { @@ -253,7 +255,7 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibEntry entry, * @param fileLink the location of the file * @throws IOException */ - public static void openFolderAndSelectFile(String fileLink) throws IOException { + public static void openFolderAndSelectFile(Path fileLink) throws IOException { NATIVE_DESKTOP.openFolderAndSelectFile(fileLink); } diff --git a/src/main/java/org/jabref/gui/desktop/os/DefaultDesktop.java b/src/main/java/org/jabref/gui/desktop/os/DefaultDesktop.java index ec94b9ae2bf..b4b99326251 100644 --- a/src/main/java/org/jabref/gui/desktop/os/DefaultDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/os/DefaultDesktop.java @@ -4,7 +4,6 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import org.apache.commons.logging.Log; @@ -24,8 +23,8 @@ public void openFileWithApplication(String filePath, String application) throws } @Override - public void openFolderAndSelectFile(String filePath) throws IOException { - File file = Paths.get(filePath).toAbsolutePath().getParent().toFile(); + public void openFolderAndSelectFile(Path filePath) throws IOException { + File file = filePath.toAbsolutePath().getParent().toFile(); Desktop.getDesktop().open(file); } diff --git a/src/main/java/org/jabref/gui/desktop/os/Linux.java b/src/main/java/org/jabref/gui/desktop/os/Linux.java index c25b22e3f6a..5abbab5cf49 100644 --- a/src/main/java/org/jabref/gui/desktop/os/Linux.java +++ b/src/main/java/org/jabref/gui/desktop/os/Linux.java @@ -50,7 +50,7 @@ public void openFileWithApplication(String filePath, String application) throws } @Override - public void openFolderAndSelectFile(String filePath) throws IOException { + public void openFolderAndSelectFile(Path filePath) throws IOException { String desktopSession = System.getenv("DESKTOP_SESSION").toLowerCase(Locale.ROOT); String cmd; @@ -60,7 +60,7 @@ public void openFolderAndSelectFile(String filePath) throws IOException { } else if (desktopSession.contains("kde")) { cmd = "dolphin --select " + filePath; } else { - cmd = "xdg-open " + Paths.get(filePath).toAbsolutePath().getParent().toString(); + cmd = "xdg-open " + filePath.toAbsolutePath().getParent().toString(); } Runtime.getRuntime().exec(cmd); diff --git a/src/main/java/org/jabref/gui/desktop/os/NativeDesktop.java b/src/main/java/org/jabref/gui/desktop/os/NativeDesktop.java index 108102e3abe..ed54cf78e0e 100644 --- a/src/main/java/org/jabref/gui/desktop/os/NativeDesktop.java +++ b/src/main/java/org/jabref/gui/desktop/os/NativeDesktop.java @@ -17,7 +17,7 @@ public interface NativeDesktop { */ void openFileWithApplication(String filePath, String application) throws IOException; - void openFolderAndSelectFile(String filePath) throws IOException; + void openFolderAndSelectFile(Path file) throws IOException; void openConsole(String absolutePath) throws IOException; diff --git a/src/main/java/org/jabref/gui/desktop/os/OSX.java b/src/main/java/org/jabref/gui/desktop/os/OSX.java index 54749b3a72b..c4a6c495431 100644 --- a/src/main/java/org/jabref/gui/desktop/os/OSX.java +++ b/src/main/java/org/jabref/gui/desktop/os/OSX.java @@ -33,9 +33,8 @@ public void openFileWithApplication(String filePath, String application) throws } @Override - public void openFolderAndSelectFile(String filePath) throws IOException { - File file = new File(filePath); - Desktop.getDesktop().open(file.getParentFile()); + public void openFolderAndSelectFile(Path file) throws IOException { + Desktop.getDesktop().open(file.getParent().toFile()); } @Override diff --git a/src/main/java/org/jabref/gui/desktop/os/Windows.java b/src/main/java/org/jabref/gui/desktop/os/Windows.java index 5fd34fd60a0..2a3f2aa3da9 100644 --- a/src/main/java/org/jabref/gui/desktop/os/Windows.java +++ b/src/main/java/org/jabref/gui/desktop/os/Windows.java @@ -59,8 +59,8 @@ public void openFileWithApplication(String filePath, String application) throws } @Override - public void openFolderAndSelectFile(String filePath) throws IOException { - new ProcessBuilder("explorer.exe", "/select,", filePath).start(); + public void openFolderAndSelectFile(Path filePath) throws IOException { + new ProcessBuilder("explorer.exe", "/select,", filePath.toString()).start(); } @Override diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java index d34210e5327..08abde5f290 100644 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java +++ b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java @@ -16,12 +16,12 @@ import org.jabref.gui.util.OnlyIntegerFormatter; import org.jabref.gui.util.TaskExecutor; import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; public class DocumentViewerController extends AbstractController { @FXML private ScrollBar scrollBar; - @FXML private ComboBox fileChoice; + @FXML private ComboBox fileChoice; @FXML private BorderPane mainPane; @FXML private ToggleButton modeLive; @FXML private TextField currentPage; @@ -59,8 +59,8 @@ private void setupPageControls() { } private void setupFileChoice() { - ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() - .withText(ParsedFileField::getLink); + ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() + .withText(LinkedFile::getLink); fileChoice.setButtonCell(cellFactory.call(null)); fileChoice.setCellFactory(cellFactory); fileChoice.getSelectionModel().selectedItemProperty().addListener( diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerViewModel.java b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerViewModel.java index c9e57f4ad3e..96fdbc9cf1c 100644 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerViewModel.java +++ b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerViewModel.java @@ -19,10 +19,8 @@ import org.jabref.Globals; import org.jabref.gui.AbstractViewModel; import org.jabref.gui.StateManager; -import org.jabref.logic.TypedBibEntry; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; import org.apache.pdfbox.pdmodel.PDDocument; import org.fxmisc.easybind.EasyBind; @@ -31,7 +29,7 @@ public class DocumentViewerViewModel extends AbstractViewModel { private StateManager stateManager; private ObjectProperty currentDocument = new SimpleObjectProperty<>(); - private ListProperty files = new SimpleListProperty<>(); + private ListProperty files = new SimpleListProperty<>(); private BooleanProperty liveMode = new SimpleBooleanProperty(); private ObjectProperty currentPage = new SimpleObjectProperty<>(); private IntegerProperty maxPages = new SimpleIntegerProperty(); @@ -79,7 +77,7 @@ public ObjectProperty currentDocumentProperty() { return currentDocument; } - public ListProperty filesProperty() { + public ListProperty filesProperty() { return files; } @@ -90,10 +88,9 @@ private void setCurrentEntries(List entries) { } } - private void setCurrentEntry(BibEntry rawEntry) { + private void setCurrentEntry(BibEntry entry) { stateManager.getActiveDatabase().ifPresent(database -> { - TypedBibEntry entry = new TypedBibEntry(rawEntry, database); - List linkedFiles = entry.getFiles(); + List linkedFiles = entry.getFiles(); // We don't need to switch to the first file, this is done automatically in the UI part files.setValue(FXCollections.observableArrayList(linkedFiles)); }); @@ -107,10 +104,10 @@ private void setCurrentDocument(Path path) { } } - public void switchToFile(ParsedFileField file) { + public void switchToFile(LinkedFile file) { if (file != null) { stateManager.getActiveDatabase().ifPresent(database -> - FileUtil.toPath(file, database, Globals.prefs.getFileDirectoryPreferences()) + file.findIn(database, Globals.prefs.getFileDirectoryPreferences()) .ifPresent(this::setCurrentDocument)); } } diff --git a/src/main/java/org/jabref/gui/externalfiles/AutoSetLinks.java b/src/main/java/org/jabref/gui/externalfiles/AutoSetLinks.java index 3c95eedec60..b9d91cf3e61 100644 --- a/src/main/java/org/jabref/gui/externalfiles/AutoSetLinks.java +++ b/src/main/java/org/jabref/gui/externalfiles/AutoSetLinks.java @@ -35,6 +35,7 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; public class AutoSetLinks { @@ -149,7 +150,7 @@ public void run() { if (!alreadyHas) { foundAny = true; Optional type; - Optional extension = FileUtil.getFileExtension(f); + Optional extension = FileHelper.getFileExtension(f); if (extension.isPresent()) { type = ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension.get()); } else { diff --git a/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java b/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java index 7f483ab490a..ed97a998ef8 100644 --- a/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java +++ b/src/main/java/org/jabref/gui/externalfiles/DroppedFileHandler.java @@ -40,6 +40,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.IdGenerator; +import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; import com.jgoodies.forms.builder.FormBuilder; @@ -422,9 +423,9 @@ private void doLink(BibEntry entry, ExternalFileType fileType, String filename, if (new File(filename).isAbsolute() || dirs.isEmpty()) { absFilename = filename; } else { - Optional file = FileUtil.expandFilename(filename, dirs); + Optional file = FileHelper.expandFilename(filename, dirs); if (file.isPresent()) { - absFilename = file.get().getAbsolutePath(); + absFilename = file.get().toAbsolutePath().toString(); } else { absFilename = ""; // This shouldn't happen based on the old code, so maybe one should set it something else? } @@ -435,17 +436,12 @@ private void doLink(BibEntry entry, ExternalFileType fileType, String filename, for (int i = 0; i < tm.getRowCount(); i++) { FileListEntry flEntry = tm.getEntry(i); // Find the absolute filename for this existing link: - String absName; - if (new File(flEntry.getLink()).isAbsolute() || dirs.isEmpty()) { - absName = flEntry.getLink(); - } else { - Optional file = FileUtil.expandFilename(flEntry.getLink(), dirs); - if (file.isPresent()) { - absName = file.get().getAbsolutePath(); - } else { - absName = null; - } - } + String absName = flEntry.toParsedFileField() + .findIn(dirs) + .map(Path::toAbsolutePath) + .map(Path::toString) + .orElse(null); + LOGGER.debug("absName: " + absName); // If the filenames are equal, we don't need to link, so we simply return: if (absFilename.equals(absName)) { diff --git a/src/main/java/org/jabref/gui/externalfiles/MoveFileAction.java b/src/main/java/org/jabref/gui/externalfiles/MoveFileAction.java index 57664f23b13..2df545575a8 100644 --- a/src/main/java/org/jabref/gui/externalfiles/MoveFileAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/MoveFileAction.java @@ -1,12 +1,8 @@ package org.jabref.gui.externalfiles; import java.awt.event.ActionEvent; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Locale; import java.util.Optional; import javax.swing.AbstractAction; @@ -19,8 +15,7 @@ import org.jabref.gui.filelist.FileListEntry; import org.jabref.logic.cleanup.MoveFilesCleanup; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; /** * Action for moving a file that is linked from an entry in JabRef. @@ -47,18 +42,14 @@ public void actionPerformed(ActionEvent event) { } FileListEntry entry = editor.getTableModel().getEntry(selected); - // Check if the current file exists: - String ln = entry.getLink(); - ParsedFileField field = entry.toParsedFileField(); + LinkedFile field = entry.toParsedFileField(); - boolean httpLink = ln.toLowerCase(Locale.ENGLISH).startsWith("http"); - if (httpLink) { + if (field.isOnlineLink()) { // TODO: notify that this operation cannot be done on remote links return; } + // Get an absolute path representation: - List dirs = frame.getCurrentBasePanel().getBibDatabaseContext() - .getFileDirectories(Globals.prefs.getFileDirectoryPreferences()); Optional fileDir = frame.getCurrentBasePanel().getBibDatabaseContext() .getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences()); if (!fileDir.isPresent()) { @@ -66,12 +57,10 @@ public void actionPerformed(ActionEvent event) { Localization.lang("Move file"), JOptionPane.ERROR_MESSAGE); return; } - Path file = Paths.get(ln); - if (!file.isAbsolute()) { - file = FileUtil.expandFilename(ln, dirs).map(File::toPath).orElse(null); - } - if ((file != null) && Files.exists(file)) { + // Check if the current file exists: + Optional file = field.findIn(frame.getCurrentBasePanel().getBibDatabaseContext(), Globals.prefs.getFileDirectoryPreferences()); + if ((file.isPresent()) && Files.exists(file.get())) { MoveFilesCleanup moveFiles = new MoveFilesCleanup(frame.getCurrentBasePanel().getBibDatabaseContext(), Globals.prefs.getCleanupPreferences(Globals.journalAbbreviationLoader).getFileDirPattern(), diff --git a/src/main/java/org/jabref/gui/externalfiles/RenameFileAction.java b/src/main/java/org/jabref/gui/externalfiles/RenameFileAction.java index f1249f67a70..be7b5da4b37 100644 --- a/src/main/java/org/jabref/gui/externalfiles/RenameFileAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/RenameFileAction.java @@ -1,12 +1,8 @@ package org.jabref.gui.externalfiles; import java.awt.event.ActionEvent; -import java.io.File; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Locale; import java.util.Optional; import javax.swing.AbstractAction; @@ -19,8 +15,7 @@ import org.jabref.gui.filelist.FileListEntry; import org.jabref.logic.cleanup.RenamePdfCleanup; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; public class RenameFileAction extends AbstractAction { @@ -44,16 +39,12 @@ public void actionPerformed(ActionEvent e) { } FileListEntry entry = editor.getTableModel().getEntry(selected); - ParsedFileField field = entry.toParsedFileField(); + LinkedFile field = entry.toParsedFileField(); // Check if the current file exists: - String ln = entry.getLink(); - boolean httpLink = ln.toLowerCase(Locale.ENGLISH).startsWith("http"); - if (httpLink) { + if (field.isOnlineLink()) { // TODO: notify that this operation cannot be done on remote links return; } - List dirs = frame.getCurrentBasePanel().getBibDatabaseContext() - .getFileDirectories(Globals.prefs.getFileDirectoryPreferences()); Optional fileDir = frame.getCurrentBasePanel().getBibDatabaseContext() .getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences()); if (!fileDir.isPresent()) { @@ -61,12 +52,9 @@ public void actionPerformed(ActionEvent e) { Localization.lang("Rename file"), JOptionPane.ERROR_MESSAGE); return; } - Path file = Paths.get(ln); - if (!file.isAbsolute()) { - file = FileUtil.expandFilename(ln, dirs).map(File::toPath).orElse(null); - } - if ((file != null) && Files.exists(file)) { + Optional file = field.findIn(frame.getCurrentBasePanel().getBibDatabaseContext(), Globals.prefs.getFileDirectoryPreferences()); + if ((file.isPresent()) && Files.exists(file.get())) { RenamePdfCleanup pdfCleanup = new RenamePdfCleanup(false, frame.getCurrentBasePanel().getBibDatabaseContext(), diff --git a/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java b/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java index a8ebc3a83c5..6ad850141af 100644 --- a/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java +++ b/src/main/java/org/jabref/gui/externalfiles/SynchronizeFileField.java @@ -2,13 +2,13 @@ import java.awt.BorderLayout; import java.awt.event.ActionEvent; -import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Optional; import java.util.Set; @@ -44,10 +44,10 @@ import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.worker.AbstractWorker; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.LinkedFile; import com.jgoodies.forms.builder.ButtonBarBuilder; import com.jgoodies.forms.builder.FormBuilder; @@ -61,15 +61,12 @@ public class SynchronizeFileField extends AbstractWorker { private final BasePanel panel; - private List sel; - private SynchronizeFileField.OptionsDialog optDiag; - - private int entriesChangedCount; - private final Object[] brokenLinkOptions = {Localization.lang("Ignore"), Localization.lang("Assign new file"), Localization.lang("Remove link"), Localization.lang("Remove all broken links"), Localization.lang("Quit synchronization")}; - + private List sel; + private SynchronizeFileField.OptionsDialog optDiag; + private int entriesChangedCount; private boolean goOn = true; private boolean autoSet = true; private boolean checkExisting = true; @@ -139,19 +136,12 @@ public void run() { FileListTableModel tableModel = new FileListTableModel(); tableModel.setContentDontGuessTypes(old.get()); - // We need to specify which directories to search in for Util.expandFilename: - List dirsS = panel.getBibDatabaseContext() - .getFileDirectories(Globals.prefs.getFileDirectoryPreferences()); - List dirs = new ArrayList<>(); - for (String dirs1 : dirsS) { - dirs.add(new File(dirs1)); - } - for (int j = 0; j < tableModel.getRowCount(); j++) { FileListEntry flEntry = tableModel.getEntry(j); + LinkedFile field = flEntry.toParsedFileField(); + // See if the link looks like an URL: - boolean httpLink = flEntry.getLink().toLowerCase(Locale.ENGLISH).startsWith("http"); - if (httpLink) { + if (field.isOnlineLink()) { continue; // Don't check the remote file. // TODO: should there be an option to check remote links? } @@ -160,8 +150,8 @@ public void run() { boolean deleted = false; // Get an absolute path representation: - Optional file = FileUtil.expandFilename(flEntry.getLink(), dirsS); - if ((!file.isPresent()) || !file.get().exists()) { + Optional file = field.findIn(panel.getBibDatabaseContext(), Globals.prefs.getFileDirectoryPreferences()); + if ((!file.isPresent()) || !Files.exists(file.get())) { int answer; if (removeAllBroken) { answer = 2; // We should delete this link. @@ -287,7 +277,6 @@ static class OptionsDialog extends JabRefDialog { private final JButton ok = new JButton(Localization.lang("OK")); private final JButton cancel = new JButton(Localization.lang("Cancel")); - private boolean canceled = true; private final BibDatabaseContext databaseContext; private final JRadioButton autoSetUnset = new JRadioButton(Localization.lang("Automatically set file links") + ". " + Localization.lang("Do not overwrite existing links."), true); @@ -295,6 +284,7 @@ static class OptionsDialog extends JabRefDialog { + ". " + Localization.lang("Allow overwriting existing links."), false); private final JRadioButton autoSetNone = new JRadioButton(Localization.lang("Do not automatically set"), false); private final JCheckBox checkLinks = new JCheckBox(Localization.lang("Check existing file links"), true); + private boolean canceled = true; public OptionsDialog(JFrame parent, BibDatabaseContext databaseContext) { diff --git a/src/main/java/org/jabref/gui/externalfiles/TransferableFileLinkSelection.java b/src/main/java/org/jabref/gui/externalfiles/TransferableFileLinkSelection.java index 94d05ccb771..4565db036dd 100644 --- a/src/main/java/org/jabref/gui/externalfiles/TransferableFileLinkSelection.java +++ b/src/main/java/org/jabref/gui/externalfiles/TransferableFileLinkSelection.java @@ -3,17 +3,15 @@ import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; -import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import org.jabref.Globals; import org.jabref.gui.BasePanel; -import org.jabref.gui.filelist.FileListTableModel; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.LinkedFile; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,21 +21,20 @@ */ public class TransferableFileLinkSelection implements Transferable { - private final List fileList = new ArrayList<>(); + private final List fileList = new ArrayList<>(); private static final Log LOGGER = LogFactory.getLog(TransferableFileLinkSelection.class); public TransferableFileLinkSelection(BasePanel panel, List selection) { - FileListTableModel tm = new FileListTableModel(); - selection.get(0).getField(FieldName.FILE).ifPresent(tm::setContent); - if (tm.getRowCount() > 0) { + BibEntry entry = selection.get(0); + List files = entry.getFiles(); + if (!files.isEmpty()) { // Find the default directory for this field type, if any: - List dirs = panel.getBibDatabaseContext() - .getFileDirectories(Globals.prefs.getFileDirectoryPreferences()); - FileUtil.expandFilename(tm.getEntry(0).getLink(), dirs).ifPresent(fileList::add); + LinkedFile firstFile = files.get(0); + firstFile.findIn(panel.getDatabaseContext(), Globals.prefs.getFileDirectoryPreferences()) + .ifPresent(fileList::add); } - } @Override diff --git a/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java b/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java index 51b007dc1c2..258e21ab846 100644 --- a/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/WriteXMPAction.java @@ -4,10 +4,12 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; -import java.io.File; -import java.util.ArrayList; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collection; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -26,16 +28,12 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefDialog; -import org.jabref.gui.filelist.FileListEntry; -import org.jabref.gui.filelist.FileListTableModel; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.worker.AbstractWorker; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; import org.jabref.logic.xmp.XMPUtil; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; import com.jgoodies.forms.builder.ButtonBarBuilder; @@ -117,29 +115,12 @@ public void run() { for (BibEntry entry : entries) { // Make a list of all PDFs linked from this entry: - List files = new ArrayList<>(); - - // First check the (legacy) "pdf" field: - entry.getField(FieldName.PDF) - .ifPresent( - pdf -> FileUtil - .expandFilename(pdf, - panel.getBibDatabaseContext().getFileDirectories(FieldName.PDF, - Globals.prefs.getFileDirectoryPreferences())) - .ifPresent(files::add)); - // Then check the "file" field: - List dirs = panel.getBibDatabaseContext() - .getFileDirectories(Globals.prefs.getFileDirectoryPreferences()); - if (entry.hasField(FieldName.FILE)) { - FileListTableModel tm = new FileListTableModel(); - entry.getField(FieldName.FILE).ifPresent(tm::setContent); - for (int j = 0; j < tm.getRowCount(); j++) { - FileListEntry flEntry = tm.getEntry(j); - if ((flEntry.getType().isPresent()) && "pdf".equalsIgnoreCase(flEntry.getType().get().getName())) { - FileUtil.expandFilename(flEntry.getLink(), dirs).ifPresent(files::add); - } - } - } + List files = entry.getFiles().stream() + .filter(file -> file.getFileType().equalsIgnoreCase("pdf")) + .map(file -> file.findIn(panel.getBibDatabaseContext(), Globals.prefs.getFileDirectoryPreferences())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); SwingUtilities.invokeLater(() -> optDiag.getProgressArea() .append(entry.getCiteKeyOptional().orElse(Localization.lang("undefined")) + "\n")); @@ -149,17 +130,17 @@ public void run() { SwingUtilities.invokeLater(() -> optDiag.getProgressArea() .append(" " + Localization.lang("Skipped - No PDF linked") + ".\n")); } else { - for (File file : files) { - if (file.exists()) { + for (Path file : files) { + if (Files.exists(file)) { try { - XMPUtil.writeXMP(file, entry, database, Globals.prefs.getXMPPreferences()); + XMPUtil.writeXMP(file.toFile(), entry, database, Globals.prefs.getXMPPreferences()); SwingUtilities.invokeLater( () -> optDiag.getProgressArea().append(" " + Localization.lang("OK") + ".\n")); entriesChanged++; } catch (Exception e) { SwingUtilities.invokeLater(() -> { optDiag.getProgressArea().append(" " + Localization.lang("Error while writing") + " '" - + file.getPath() + "':\n"); + + file.toString() + "':\n"); optDiag.getProgressArea().append(" " + e.getLocalizedMessage() + "\n"); }); errors++; @@ -169,7 +150,7 @@ public void run() { SwingUtilities.invokeLater(() -> { optDiag.getProgressArea() .append(" " + Localization.lang("Skipped - PDF does not exist") + ":\n"); - optDiag.getProgressArea().append(" " + file.getPath() + "\n"); + optDiag.getProgressArea().append(" " + file.toString() + "\n"); }); } } diff --git a/src/main/java/org/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java b/src/main/java/org/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java index c17400a5519..c25731b9a2a 100644 --- a/src/main/java/org/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java @@ -1,10 +1,12 @@ package org.jabref.gui.externalfiles; import java.awt.event.ActionEvent; -import java.io.File; import java.io.IOException; -import java.util.ArrayList; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.Action; @@ -14,14 +16,10 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.IconTheme; import org.jabref.gui.entryeditor.EntryEditor; -import org.jabref.gui.filelist.FileListEntry; -import org.jabref.gui.filelist.FileListTableModel; import org.jabref.gui.worker.AbstractWorker; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; import org.jabref.logic.xmp.XMPUtil; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; /** * Write XMP action for EntryEditor toolbar. @@ -51,26 +49,12 @@ public void actionPerformed(ActionEvent actionEvent) { BibEntry entry = editor.getEntry(); // Make a list of all PDFs linked from this entry: - List files = new ArrayList<>(); - - // First check the (legacy) "pdf" field: - entry.getField(FieldName.PDF) - .ifPresent(pdf -> FileUtil.expandFilename(pdf, panel.getBibDatabaseContext() - .getFileDirectories(FieldName.PDF, Globals.prefs.getFileDirectoryPreferences())) - .ifPresent(files::add)); - - // Then check the "file" field: - List dirs = panel.getBibDatabaseContext().getFileDirectories(Globals.prefs.getFileDirectoryPreferences()); - if (entry.hasField(FieldName.FILE)) { - FileListTableModel tm = new FileListTableModel(); - entry.getField(FieldName.FILE).ifPresent(tm::setContent); - for (int j = 0; j < tm.getRowCount(); j++) { - FileListEntry flEntry = tm.getEntry(j); - if ((flEntry.getType().isPresent()) && "pdf".equalsIgnoreCase(flEntry.getType().get().getName())) { - FileUtil.expandFilename(flEntry.getLink(), dirs).ifPresent(files::add); - } - } - } + List files = entry.getFiles().stream() + .filter(file -> file.getFileType().equalsIgnoreCase("pdf")) + .map(file -> file.findIn(panel.getBibDatabaseContext(), Globals.prefs.getFileDirectoryPreferences())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); // We want to offload the actual work to a background thread, so we have a worker // thread: @@ -88,11 +72,11 @@ public void actionPerformed(ActionEvent actionEvent) { class WriteXMPWorker extends AbstractWorker { - private final List files; + private final List files; private final BibEntry entry; - public WriteXMPWorker(List files, BibEntry entry) { + public WriteXMPWorker(List files, BibEntry entry) { this.files = files; this.entry = entry; @@ -105,8 +89,8 @@ public void run() { } else { int written = 0; int error = 0; - for (File file : files) { - if (!file.exists()) { + for (Path file : files) { + if (!Files.exists(file)) { if (files.size() == 1) { message = Localization.lang("PDF does not exist"); } @@ -114,14 +98,14 @@ public void run() { } else { try { - XMPUtil.writeXMP(file, entry, panel.getDatabase(), Globals.prefs.getXMPPreferences()); + XMPUtil.writeXMP(file.toFile(), entry, panel.getDatabase(), Globals.prefs.getXMPPreferences()); if (files.size() == 1) { message = Localization.lang("Wrote XMP-metadata"); } written++; } catch (IOException | TransformerException e) { if (files.size() == 1) { - message = Localization.lang("Error while writing") + " '" + file.getPath() + "'"; + message = Localization.lang("Error while writing") + " '" + file.toString() + "'"; } error++; diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileMenuItem.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileMenuItem.java index 52d9a796423..0d5338391a6 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileMenuItem.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileMenuItem.java @@ -12,9 +12,9 @@ import org.jabref.gui.JabRefFrame; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.model.util.FileHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -67,7 +67,7 @@ private boolean openLink() { if (!this.fileType.isPresent()) { if (this.fieldName == null) { // We don't already know the file type, so we try to deduce it from the extension: - Optional extension = FileUtil.getFileExtension(link); + Optional extension = FileHelper.getFileExtension(link); // Now we know the extension, check if it is one we know about: type = ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension.orElse(null)); fileType = type; diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java index 5e24f6e5e04..486bd50faf4 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java @@ -10,7 +10,7 @@ import org.jabref.Globals; import org.jabref.gui.IconTheme; import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.FileField; +import org.jabref.model.entry.FileFieldWriter; import org.jabref.model.strings.StringUtil; import org.jabref.preferences.JabRefPreferences; @@ -263,7 +263,7 @@ public void setExternalFileTypes(List types) { array[i] = new String[] {type.getName(), FILE_TYPE_REMOVED_FLAG}; i++; } - Globals.prefs.put(JabRefPreferences.EXTERNAL_FILE_TYPES, FileField.encodeStringArray(array)); + Globals.prefs.put(JabRefPreferences.EXTERNAL_FILE_TYPES, FileFieldWriter.encodeStringArray(array)); } /** diff --git a/src/main/java/org/jabref/gui/fieldeditors/FileListEditor.java b/src/main/java/org/jabref/gui/fieldeditors/FileListEditor.java index 8ee9214dad8..c04046c874d 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FileListEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FileListEditor.java @@ -8,7 +8,6 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -51,7 +50,6 @@ import org.jabref.gui.filelist.FileListTableModel; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -137,22 +135,22 @@ public FileListEditor(JabRefFrame frame, BibDatabaseContext databaseContext, Str if (row >= 0) { FileListEntry entry = tableModel.getEntry(row); try { - String path = ""; + Path path = null; // absolute path if (Paths.get(entry.getLink()).isAbsolute()) { - path = Paths.get(entry.getLink()).toString(); + path = Paths.get(entry.getLink()); } else { // relative to file folder for (String folder : databaseContext .getFileDirectories(Globals.prefs.getFileDirectoryPreferences())) { Path file = Paths.get(folder, entry.getLink()); if (Files.exists(file)) { - path = file.toString(); + path = file; break; } } } - if (!path.isEmpty()) { + if (path != null) { JabRefDesktop.openFolderAndSelectFile(path); } else { JOptionPane.showMessageDialog(frame, @@ -185,13 +183,11 @@ public FileListEditor(JabRefFrame frame, BibDatabaseContext databaseContext, Str } FileListEntry entry = tableModel.getEntry(row); - Optional file = FileUtil.expandFilename(databaseContext, entry.getLink(), - Globals.prefs.getFileDirectoryPreferences()); - + Optional file = entry.toParsedFileField().findIn(databaseContext, Globals.prefs.getFileDirectoryPreferences()); if (file.isPresent()) { String[] options = {Localization.lang("Delete"), Localization.lang("Cancel")}; int userConfirm = JOptionPane.showOptionDialog(frame, - Localization.lang("Delete '%0'?", file.get().getName()), + Localization.lang("Delete '%0'?", file.get().getFileName().toString()), Localization.lang("Delete file"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, @@ -201,7 +197,7 @@ public FileListEditor(JabRefFrame frame, BibDatabaseContext databaseContext, Str if (userConfirm == JOptionPane.YES_OPTION) { try { - Files.delete(file.get().toPath()); + Files.delete(file.get()); removeEntries(); } catch (IOException ex) { JOptionPane.showMessageDialog(frame, Localization.lang("File permission error"), diff --git a/src/main/java/org/jabref/gui/fieldeditors/FileListEditorTransferHandler.java b/src/main/java/org/jabref/gui/fieldeditors/FileListEditorTransferHandler.java index d71b083fc4e..5e0e9ffcf36 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FileListEditorTransferHandler.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FileListEditorTransferHandler.java @@ -5,9 +5,9 @@ import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; -import java.io.File; import java.io.IOException; import java.net.URL; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ import org.jabref.gui.externalfiles.DroppedFileHandler; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.groups.EntryTableTransferHandler; -import org.jabref.logic.util.io.FileUtil; +import org.jabref.model.util.FileHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -79,11 +79,11 @@ public boolean importData(JComponent comp, Transferable t) { try { - List files = new ArrayList<>(); + List files = new ArrayList<>(); // This flavor is used for dragged file links in Windows: if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { @SuppressWarnings("unchecked") - List transferedFiles = (List) t.getTransferData(DataFlavor.javaFileListFlavor); + List transferedFiles = (List) t.getTransferData(DataFlavor.javaFileListFlavor); files.addAll(transferedFiles); } @@ -100,10 +100,10 @@ public boolean importData(JComponent comp, Transferable t) { } SwingUtilities.invokeLater(() -> { - for (File file : files) { + for (Path file : files) { // Find the file's extension, if any: - String name = file.getAbsolutePath(); - FileUtil.getFileExtension(name).ifPresent(extension -> ExternalFileTypes.getInstance() + String name = file.toAbsolutePath().toString(); + FileHelper.getFileExtension(name).ifPresent(extension -> ExternalFileTypes.getInstance() .getExternalFileTypeByExt(extension).ifPresent(fileType -> { if (droppedFileHandler == null) { droppedFileHandler = new DroppedFileHandler(frame, frame.getCurrentBasePanel()); diff --git a/src/main/java/org/jabref/gui/filelist/FileListEntry.java b/src/main/java/org/jabref/gui/filelist/FileListEntry.java index 0e3a84a534e..3a5c11e33a7 100644 --- a/src/main/java/org/jabref/gui/filelist/FileListEntry.java +++ b/src/main/java/org/jabref/gui/filelist/FileListEntry.java @@ -4,7 +4,7 @@ import java.util.Optional; import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; /** * This class represents a file link for a Bibtex entry. */ @@ -45,8 +45,8 @@ public String toString() { return getDescription() + " : " + getLink() + " : " + getType().orElse(null); } - public ParsedFileField toParsedFileField() { - return new ParsedFileField(getDescription(), getLink(), getType().isPresent() ? getType().get().getName() : ""); + public LinkedFile toParsedFileField() { + return new LinkedFile(getDescription(), getLink(), getType().isPresent() ? getType().get().getName() : ""); } public String getDescription() { diff --git a/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java b/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java index 68f00784bb1..5d30e7bfcce 100644 --- a/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java +++ b/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java @@ -45,6 +45,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; import com.jgoodies.forms.builder.ButtonBarBuilder; @@ -84,8 +85,6 @@ public class FileListEntryEditor { private boolean openBrowseWhenShown; private boolean dontOpenBrowseUntilDisposed; - //Do not make this variable final, as then the lambda action listener will fail on compile - private JabRefFrame frame; private boolean showSaveDialog; private static final Pattern REMOTE_LINK_PATTERN = Pattern.compile("[a-z]+://.*"); @@ -101,7 +100,6 @@ public FileListEntryEditor(JabRefFrame frame, FileListEntry entry, boolean showP BibDatabaseContext databaseContext) { this.entry = entry; this.databaseContext = databaseContext; - this.frame = frame; ActionListener okAction = e -> { // If OK button is disabled, ignore this event: @@ -355,20 +353,14 @@ public boolean okPressed() { private final ActionListener browsePressed = e -> { String fileText = link.getText().trim(); - Optional file = FileUtil.expandFilename(this.databaseContext, fileText, + Optional file = FileHelper.expandFilename(this.databaseContext, fileText, Globals.prefs.getFileDirectoryPreferences()); - String workingDir; - // no file set yet or found - if (file.isPresent()) { - workingDir = file.get().getPath(); - } else { - workingDir = Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY); - } + Path workingDir = file.orElse(Paths.get(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))); String fileName = Paths.get(fileText).getFileName().toString(); FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .withInitialDirectory(Paths.get(workingDir)) + .withInitialDirectory(workingDir) .withInitialFileName(fileName).build(); DialogService ds = new FXDialogService(); diff --git a/src/main/java/org/jabref/gui/filelist/FileListTableModel.java b/src/main/java/org/jabref/gui/filelist/FileListTableModel.java index 0941da690c0..fc415c27664 100644 --- a/src/main/java/org/jabref/gui/filelist/FileListTableModel.java +++ b/src/main/java/org/jabref/gui/filelist/FileListTableModel.java @@ -13,9 +13,10 @@ import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.externalfiletype.UnknownExternalFileType; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldParser; +import org.jabref.model.entry.FileFieldWriter; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.util.FileHelper; /** * Data structure to contain a list of file links, parseable from a coded string. @@ -119,10 +120,10 @@ private FileListEntry setContent(String val, boolean firstOnly, boolean deduceUn value = ""; } - List fields = FileField.parse(value); + List fields = FileFieldParser.parse(value); List files = new ArrayList<>(); - for(ParsedFileField entry : fields) { + for(LinkedFile entry : fields) { if (entry.isEmpty()) { continue; } @@ -161,7 +162,7 @@ public static JLabel getFirstLabel(String content) { return entry.getType().get().getIconLabel(); } - private FileListEntry decodeEntry(ParsedFileField entry, boolean deduceUnknownType) { + private FileListEntry decodeEntry(LinkedFile entry, boolean deduceUnknownType) { Optional type = ExternalFileTypes.getInstance().getExternalFileTypeByName(entry.getFileType()); if (deduceUnknownType && (type.get() instanceof UnknownExternalFileType)) { @@ -170,7 +171,7 @@ private FileListEntry decodeEntry(ParsedFileField entry, boolean deduceUnknownTy type = ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(entry.getFileType()); if (!type.isPresent()) { // No type could be found from mime type on the extension: - Optional extension = FileUtil.getFileExtension(entry.getLink()); + Optional extension = FileHelper.getFileExtension(entry.getLink()); if (extension.isPresent()) { Optional typeGuess = ExternalFileTypes.getInstance() .getExternalFileTypeByExt(extension.get()); @@ -198,7 +199,7 @@ public String getStringRepresentation() { array[i] = entry.getStringArrayRepresentation(); i++; } - return FileField.encodeStringArray(array); + return FileFieldWriter.encodeStringArray(array); } } diff --git a/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java b/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java index 84d0844cd5d..a5f138cf955 100644 --- a/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java +++ b/src/main/java/org/jabref/gui/groups/EntryTableTransferHandler.java @@ -13,6 +13,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,7 +34,7 @@ import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.maintable.MainTable; import org.jabref.logic.net.URLDownload; -import org.jabref.logic.util.io.FileUtil; +import org.jabref.model.util.FileHelper; import org.jabref.pdfimport.PdfImporter; import org.jabref.pdfimport.PdfImporter.ImportPdfFilesResult; @@ -117,8 +118,8 @@ public boolean importData(JComponent comp, Transferable t) { // JOptionPane.showMessageDialog(null, "Received // javaFileListFlavor"); @SuppressWarnings("unchecked") - List l = (List) t.getTransferData(DataFlavor.javaFileListFlavor); - return handleDraggedFiles(l, dropRow); + List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor); + return handleDraggedFiles(files, dropRow); } else if (t.isDataFlavorSupported(urlFlavor)) { URL dropLink = (URL) t.getTransferData(urlFlavor); return handleDropTransfer(dropLink); @@ -230,10 +231,10 @@ private boolean handleDropTransfer(String dropStr, final int dropRow) throws IOE * @return a List containing the individual file objects. * */ - public static List getFilesFromDraggedFilesString(String s) { + public static List getFilesFromDraggedFilesString(String s) { // Split into lines: String[] lines = s.replace("\r", "").split("\n"); - List files = new ArrayList<>(); + List files = new ArrayList<>(); for (String line1 : lines) { String line = line1; @@ -263,7 +264,7 @@ public static List getFilesFromDraggedFilesString(String s) { File f = new File(line); if (f.exists()) { - files.add(f); + files.add(f.toPath()); } } return files; @@ -290,10 +291,10 @@ private boolean handleDraggedFilenames(String s, final int dropRow) { * @param dropRow @param dropRow The row in the table where the files were dragged. * @return success status for the operation */ - private boolean handleDraggedFiles(List files, final int dropRow) { + private boolean handleDraggedFiles(List files, final int dropRow) { final List fileNames = new ArrayList<>(); - for (File file : files) { - fileNames.add(file.getAbsolutePath()); + for (Path file : files) { + fileNames.add(file.toAbsolutePath().toString()); } // Try to load BIB files normally, and import the rest into the current // database. @@ -323,7 +324,7 @@ private void loadOrImportFiles(List fileNames, int dropRow) { List bibFiles = new ArrayList<>(); for (String fileName : fileNames) { // Find the file's extension, if any: - Optional extension = FileUtil.getFileExtension(fileName); + Optional extension = FileHelper.getFileExtension(fileName); Optional fileType; if (extension.isPresent() && "bib".equals(extension.get())) { diff --git a/src/main/java/org/jabref/gui/worker/SendAsEMailAction.java b/src/main/java/org/jabref/gui/worker/SendAsEMailAction.java index 620887a4330..7240f191ab4 100644 --- a/src/main/java/org/jabref/gui/worker/SendAsEMailAction.java +++ b/src/main/java/org/jabref/gui/worker/SendAsEMailAction.java @@ -1,11 +1,11 @@ package org.jabref.gui.worker; import java.awt.Desktop; -import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -82,13 +82,13 @@ public void run() { // the unofficial "mailto:attachment" property boolean openFolders = JabRefPreferences.getInstance().getBoolean(JabRefPreferences.OPEN_FOLDERS_OF_ATTACHED_FILES); - List fileList = FileUtil.getListOfLinkedFiles(bes, frame.getCurrentBasePanel().getBibDatabaseContext() + List fileList = FileUtil.getListOfLinkedFiles(bes, frame.getCurrentBasePanel().getBibDatabaseContext() .getFileDirectories(Globals.prefs.getFileDirectoryPreferences())); - for (File f : fileList) { - attachments.add(f.getPath()); + for (Path f : fileList) { + attachments.add(f.toAbsolutePath().toString()); if (openFolders) { try { - JabRefDesktop.openFolderAndSelectFile(f.getAbsolutePath()); + JabRefDesktop.openFolderAndSelectFile(f.toAbsolutePath()); } catch (IOException e) { LOGGER.debug("Cannot open file", e); } diff --git a/src/main/java/org/jabref/logic/TypedBibEntry.java b/src/main/java/org/jabref/logic/TypedBibEntry.java index f371fa7974b..735a84d8035 100644 --- a/src/main/java/org/jabref/logic/TypedBibEntry.java +++ b/src/main/java/org/jabref/logic/TypedBibEntry.java @@ -1,7 +1,5 @@ package org.jabref.logic; -import java.util.ArrayList; -import java.util.List; import java.util.Objects; import java.util.Optional; @@ -11,9 +9,6 @@ import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.EntryType; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; import org.jabref.model.strings.StringUtil; /** @@ -63,20 +58,4 @@ public String getTypeForDisplay() { return StringUtil.capitalizeFirst(entry.getType()); } } - - /** - * Gets a list of linked files. - * - * @return the list of linked files, is never null but can be empty - */ - public List getFiles() { - //Extract the path - Optional oldValue = entry.getField(FieldName.FILE); - if (!oldValue.isPresent()) { - return new ArrayList<>(); - } - - return FileField.parse(oldValue.get()); - } - } diff --git a/src/main/java/org/jabref/logic/cleanup/FileLinksCleanup.java b/src/main/java/org/jabref/logic/cleanup/FileLinksCleanup.java index 2a6e097b15b..cd28951141a 100644 --- a/src/main/java/org/jabref/logic/cleanup/FileLinksCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/FileLinksCleanup.java @@ -8,8 +8,8 @@ import org.jabref.model.cleanup.CleanupJob; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldWriter; +import org.jabref.model.entry.LinkedFile; /** * Fixes the format of the file field. For example, if the file link is empty but the description wrongly contains the path. @@ -23,10 +23,10 @@ public List cleanup(BibEntry entry) { return Collections.emptyList(); } - List fileList = FileField.parse(oldValue.get()); + List fileList = entry.getFiles(); // Parsing automatically moves a single description to link, so we just need to write the fileList back again - String newValue = FileField.getStringRepresentation(fileList); + String newValue = FileFieldWriter.getStringRepresentation(fileList); if (!oldValue.get().equals(newValue)) { entry.setField(FieldName.FILE, newValue); FieldChange change = new FieldChange(entry, FieldName.FILE, oldValue.get(), newValue); diff --git a/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java b/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java index c5a0e1b9ec2..42dafd86d59 100644 --- a/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/MoveFilesCleanup.java @@ -1,6 +1,5 @@ package org.jabref.logic.cleanup; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -13,15 +12,15 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.jabref.logic.TypedBibEntry; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.FieldChange; import org.jabref.model.cleanup.CleanupJob; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.model.util.FileHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -35,7 +34,7 @@ public class MoveFilesCleanup implements CleanupJob { private final String fileDirPattern; private static final Log LOGGER = LogFactory.getLog(MoveFilesCleanup.class); - private ParsedFileField singleFileFieldCleanup; + private LinkedFile singleFileFieldCleanup; public MoveFilesCleanup(BibDatabaseContext databaseContext, String fileDirPattern, FileDirectoryPreferences fileDirectoryPreferences, LayoutFormatterPreferences layoutPrefs) { @@ -47,7 +46,7 @@ public MoveFilesCleanup(BibDatabaseContext databaseContext, String fileDirPatter public MoveFilesCleanup(BibDatabaseContext databaseContext, String fileDirPattern, FileDirectoryPreferences fileDirectoryPreferences, LayoutFormatterPreferences prefs, - ParsedFileField field) { + LinkedFile field) { this(databaseContext, fileDirPattern, fileDirectoryPreferences, prefs); this.singleFileFieldCleanup = field; @@ -63,32 +62,31 @@ public List cleanup(BibEntry entry) { List paths = databaseContext.getFileDirectories(fileDirectoryPreferences); String defaultFileDirectory = firstExistingFileDir.get().toString(); - Optional targetDirectory = FileUtil.expandFilename(defaultFileDirectory, paths).map(File::toPath); + Optional targetDirectory = FileHelper.expandFilename(defaultFileDirectory, paths); if (!targetDirectory.isPresent()) { return Collections.emptyList(); } - TypedBibEntry typedEntry = new TypedBibEntry(entry, databaseContext); - List fileList; - List newFileList; + List fileList; + List newFileList; if (singleFileFieldCleanup != null) { fileList = Arrays.asList(singleFileFieldCleanup); //Add all other except the current selected file - newFileList = typedEntry.getFiles().stream().filter(name -> !name.equals(singleFileFieldCleanup)) + newFileList = entry.getFiles().stream().filter(name -> !name.equals(singleFileFieldCleanup)) .collect(Collectors.toList()); } else { newFileList = new ArrayList<>(); - fileList = typedEntry.getFiles(); + fileList = entry.getFiles(); } boolean changed = false; - for (ParsedFileField fileEntry : fileList) { + for (LinkedFile fileEntry : fileList) { String oldFileName = fileEntry.getLink(); - Optional oldFile = FileUtil.expandFilename(oldFileName, paths); - if (!oldFile.isPresent() || !oldFile.get().exists()) { + Optional oldFile = fileEntry.findIn(paths); + if (!oldFile.isPresent() || !Files.exists(oldFile.get())) { newFileList.add(fileEntry); continue; } @@ -98,7 +96,7 @@ public List cleanup(BibEntry entry) { layoutPrefs); } - Path newTargetFile = targetDirectory.get().resolve(targetDirName).resolve(oldFile.get().getName()); + Path newTargetFile = targetDirectory.get().resolve(targetDirName).resolve(oldFile.get().getFileName()); if (Files.exists(newTargetFile)) { // We do not overwrite already existing files newFileList.add(fileEntry); @@ -113,13 +111,13 @@ public List cleanup(BibEntry entry) { LOGGER.error("Could no create necessary target directoires for renaming", e); } - if (FileUtil.renameFile(oldFile.get().toPath(), newTargetFile, true)) { + if (FileUtil.renameFile(oldFile.get(), newTargetFile, true)) { changed = true; String newEntryFilePath = Paths.get(defaultFileDirectory).relativize(newTargetFile).toString(); - ParsedFileField newFileEntry = fileEntry; + LinkedFile newFileEntry = fileEntry; if (!oldFileName.equals(newTargetFile.toString())) { - newFileEntry = new ParsedFileField(fileEntry.getDescription(), newEntryFilePath, + newFileEntry = new LinkedFile(fileEntry.getDescription(), newEntryFilePath, fileEntry.getFileType()); changed = true; } diff --git a/src/main/java/org/jabref/logic/cleanup/RelativePathsCleanup.java b/src/main/java/org/jabref/logic/cleanup/RelativePathsCleanup.java index b175919c197..86ba8544a4c 100644 --- a/src/main/java/org/jabref/logic/cleanup/RelativePathsCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/RelativePathsCleanup.java @@ -7,13 +7,12 @@ import java.util.Objects; import java.util.Optional; -import org.jabref.logic.TypedBibEntry; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.FieldChange; import org.jabref.model.cleanup.CleanupJob; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; public class RelativePathsCleanup implements CleanupJob { @@ -29,20 +28,19 @@ public RelativePathsCleanup(BibDatabaseContext databaseContext, FileDirectoryPre @Override public List cleanup(BibEntry entry) { - TypedBibEntry typedEntry = new TypedBibEntry(entry, databaseContext); - List fileList = typedEntry.getFiles(); - List newFileList = new ArrayList<>(); + List fileList = entry.getFiles(); + List newFileList = new ArrayList<>(); boolean changed = false; - for (ParsedFileField fileEntry : fileList) { + for (LinkedFile fileEntry : fileList) { String oldFileName = fileEntry.getLink(); String newFileName = FileUtil .shortenFileName(new File(oldFileName), databaseContext.getFileDirectories(fileDirectoryPreferences)) .toString(); - ParsedFileField newFileEntry = fileEntry; + LinkedFile newFileEntry = fileEntry; if (!oldFileName.equals(newFileName)) { - newFileEntry = new ParsedFileField(fileEntry.getDescription(), newFileName, fileEntry.getFileType()); + newFileEntry = new LinkedFile(fileEntry.getDescription(), newFileName, fileEntry.getFileType()); changed = true; } newFileList.add(newFileEntry); diff --git a/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java b/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java index 705bc4419ef..f3e32edcb4f 100644 --- a/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/RenamePdfCleanup.java @@ -1,6 +1,5 @@ package org.jabref.logic.cleanup; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -13,15 +12,15 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.jabref.logic.TypedBibEntry; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.FieldChange; import org.jabref.model.cleanup.CleanupJob; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.model.util.FileHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,7 +35,7 @@ public class RenamePdfCleanup implements CleanupJob { private final LayoutFormatterPreferences layoutPrefs; private final FileDirectoryPreferences fileDirectoryPreferences; private int unsuccessfulRenames; - private ParsedFileField singleFieldCleanup; + private LinkedFile singleFieldCleanup; public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseContext, String fileNamePattern, LayoutFormatterPreferences layoutPrefs, @@ -50,7 +49,7 @@ public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseCo public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseContext, String fileNamePattern, LayoutFormatterPreferences layoutPrefs, - FileDirectoryPreferences fileDirectoryPreferences, ParsedFileField singleField) { + FileDirectoryPreferences fileDirectoryPreferences, LinkedFile singleField) { this(onlyRelativePaths, databaseContext, fileNamePattern, layoutPrefs, fileDirectoryPreferences); @@ -60,22 +59,21 @@ public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseCo @Override public List cleanup(BibEntry entry) { - TypedBibEntry typedEntry = new TypedBibEntry(entry, databaseContext); - List newFileList; - List fileList; + List newFileList; + List fileList; if (singleFieldCleanup != null) { fileList = Arrays.asList(singleFieldCleanup); - newFileList = typedEntry.getFiles().stream().filter(x -> !x.equals(singleFieldCleanup)) + newFileList = entry.getFiles().stream().filter(x -> !x.equals(singleFieldCleanup)) .collect(Collectors.toList()); } else { newFileList = new ArrayList<>(); - fileList = typedEntry.getFiles(); + fileList = entry.getFiles(); } boolean changed = false; - for (ParsedFileField flEntry : fileList) { + for (LinkedFile flEntry : fileList) { String realOldFilename = flEntry.getLink(); if (onlyRelativePaths && Paths.get(realOldFilename).isAbsolute()) { @@ -84,8 +82,7 @@ public List cleanup(BibEntry entry) { } //old path and old filename - Optional expandedOldFile = FileUtil.expandFilename(realOldFilename, - databaseContext.getFileDirectories(fileDirectoryPreferences)).map(File::toPath); + Optional expandedOldFile = flEntry.findIn(databaseContext, fileDirectoryPreferences); if ((!expandedOldFile.isPresent()) || (expandedOldFile.get().getParent() == null)) { // something went wrong. Just skip this entry @@ -137,7 +134,7 @@ public List cleanup(BibEntry entry) { } else { newFileEntryFileName = parent.relativize(newPath).toString(); } - newFileList.add(new ParsedFileField(description, newFileEntryFileName, type)); + newFileList.add(new LinkedFile(description, newFileEntryFileName, type)); } } else { unsuccessfulRenames++; @@ -157,14 +154,14 @@ public List cleanup(BibEntry entry) { return Collections.emptyList(); } - public String getTargetFileName(ParsedFileField flEntry, BibEntry entry) { + public String getTargetFileName(LinkedFile flEntry, BibEntry entry) { String realOldFilename = flEntry.getLink(); StringBuilder targetFileName = new StringBuilder(FileUtil .createFileNameFromPattern(databaseContext.getDatabase(), entry, fileNamePattern, layoutPrefs) .trim()); //Add extension to newFilename - targetFileName.append('.').append(FileUtil.getFileExtension(realOldFilename).orElse("pdf")); + targetFileName.append('.').append(FileHelper.getFileExtension(realOldFilename).orElse("pdf")); return targetFileName.toString(); } diff --git a/src/main/java/org/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java b/src/main/java/org/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java index 222682b9a8a..1cfc633630e 100644 --- a/src/main/java/org/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java +++ b/src/main/java/org/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java @@ -10,8 +10,8 @@ import org.jabref.model.cleanup.CleanupJob; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldWriter; +import org.jabref.model.entry.LinkedFile; /** * Collects file links from the ps and pdf fields, and add them to the list contained in the file field. @@ -34,7 +34,7 @@ public List cleanup(BibEntry entry) { // If there are already links in the file field, keep those on top: String oldFileContent = entry.getField(FieldName.FILE).orElse(null); - List fileList = new ArrayList<>(FileField.parse(oldFileContent)); + List fileList = new ArrayList<>(entry.getFiles()); int oldItemCount = fileList.size(); for (Map.Entry field : fields.entrySet()) { entry.getField(field.getKey()).ifPresent(o -> { @@ -42,7 +42,7 @@ public List cleanup(BibEntry entry) { return; } File f = new File(o); - ParsedFileField flEntry = new ParsedFileField(f.getName(), o, field.getValue()); + LinkedFile flEntry = new LinkedFile(f.getName(), o, field.getValue()); fileList.add(flEntry); entry.clearField(field.getKey()); @@ -51,7 +51,7 @@ public List cleanup(BibEntry entry) { } if (fileList.size() != oldItemCount) { - String newValue = FileField.getStringRepresentation(fileList); + String newValue = FileFieldWriter.getStringRepresentation(fileList); entry.setField(FieldName.FILE, newValue); changes.add(new FieldChange(entry, FieldName.FILE, oldFileContent, newValue)); } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java b/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java index af617d5c289..bbcbd7335bd 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java @@ -29,7 +29,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.identifier.ArXivIdentifier; import org.jabref.model.entry.identifier.DOI; import org.jabref.model.strings.StringUtil; @@ -398,7 +398,7 @@ public BibEntry toBibEntry(Character keywordDelimiter) { primaryCategory.ifPresent(category -> bibEntry.setField(FieldName.EPRINTCLASS, category)); journalReferenceText.ifPresent(journal -> bibEntry.setField(FieldName.JOURNALTITLE, journal)); getPdfUrl().ifPresent(url -> bibEntry - .setFiles(Collections.singletonList(new ParsedFileField("online", url, "PDF")))); + .setFiles(Collections.singletonList(new LinkedFile("online", url, "PDF")))); return bibEntry; } } diff --git a/src/main/java/org/jabref/logic/integrity/FileChecker.java b/src/main/java/org/jabref/logic/integrity/FileChecker.java index a974d83e98b..38049a3c284 100644 --- a/src/main/java/org/jabref/logic/integrity/FileChecker.java +++ b/src/main/java/org/jabref/logic/integrity/FileChecker.java @@ -1,15 +1,15 @@ package org.jabref.logic.integrity; -import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldParser; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; public class FileChecker implements ValueChecker { @@ -26,13 +26,13 @@ public FileChecker(BibDatabaseContext context, FileDirectoryPreferences fileDire @Override public Optional checkValue(String value) { - List parsedFileFields = FileField.parse(value).stream() - .filter(p -> !(p.getLink().startsWith("http://") || p.getLink().startsWith("https://"))) + List linkedFiles = FileFieldParser.parse(value).stream() + .filter(file -> !file.isOnlineLink()) .collect(Collectors.toList()); - for (ParsedFileField p : parsedFileFields) { - Optional file = FileUtil.expandFilename(context, p.getLink(), fileDirectoryPreferences); - if ((!file.isPresent()) || !file.get().exists()) { + for (LinkedFile file : linkedFiles) { + Optional linkedFile = file.findIn(context, fileDirectoryPreferences); + if ((!linkedFile.isPresent()) || !Files.exists(linkedFile.get())) { return Optional.of(Localization.lang("link should refer to a correct file path")); } } 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 b98a9c01ecc..18aa73ac505 100644 --- a/src/main/java/org/jabref/logic/layout/format/FileLink.java +++ b/src/main/java/org/jabref/logic/layout/format/FileLink.java @@ -1,14 +1,10 @@ package org.jabref.logic.layout.format; -import java.io.File; -import java.io.IOException; import java.util.List; -import java.util.Optional; import org.jabref.logic.layout.ParamLayoutFormatter; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldParser; +import org.jabref.model.entry.LinkedFile; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -35,20 +31,20 @@ public String format(String field) { return ""; } - List fileList = FileField.parse(field); + List fileList = FileFieldParser.parse(field); - String link = null; + LinkedFile link = null; if (fileType == null) { // No file type specified. Simply take the first link. if (!(fileList.isEmpty())) { - link = fileList.get(0).getLink(); + link = fileList.get(0); } } else { // A file type is specified: - for (ParsedFileField flEntry : fileList) { + for (LinkedFile flEntry : fileList) { if (flEntry.getFileType().equalsIgnoreCase(fileType)) { - link = flEntry.getLink(); + link = flEntry; break; } } @@ -69,23 +65,9 @@ public String format(String field) { dirs = prefs.getFileDirForDatabase(); } - Optional f = FileUtil.expandFilename(link, dirs); - - /* - * Stumbled over this while investigating - * - * https://sourceforge.net/tracker/index.php?func=detail&aid=1469903&group_id=92314&atid=600306 - */ - if (f.isPresent()) { - try { - return f.get().getCanonicalPath();//f.toURI().toString(); - } catch (IOException e) { - LOGGER.warn("Problem getting path", e); - return f.get().getPath(); - } - } else { - return link; - } + return link.findIn(dirs) + .map(path -> path.normalize().toString()) + .orElse(link.getLink()); } 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 5d0493dade2..d312a2ceb9b 100644 --- a/src/main/java/org/jabref/logic/layout/format/WrapFileLinks.java +++ b/src/main/java/org/jabref/logic/layout/format/WrapFileLinks.java @@ -1,17 +1,14 @@ package org.jabref.logic.layout.format; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import org.jabref.logic.layout.AbstractParamLayoutFormatter; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldParser; +import org.jabref.model.entry.LinkedFile; +import org.jabref.model.util.FileHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -81,12 +78,6 @@ public class WrapFileLinks extends AbstractParamLayoutFormatter { private static final Log LOGGER = LogFactory.getLog(WrapFileLinks.class); - - private String fileType; - private List format; - private final Map replacements = new HashMap<>(); - - // Define codes for the various escape sequences that can be inserted: private static final int STRING = 0; private static final int ITERATION_COUNT = 1; @@ -95,12 +86,9 @@ public class WrapFileLinks extends AbstractParamLayoutFormatter { private static final int FILE_EXTENSION = 4; private static final int FILE_DESCRIPTION = 5; private static final int RELATIVE_FILE_PATH = 6; - // Define which escape sequences give what results: private static final Map ESCAPE_SEQ = new HashMap<>(); - private final FileLinkPreferences prefs; - static { WrapFileLinks.ESCAPE_SEQ.put('i', WrapFileLinks.ITERATION_COUNT); WrapFileLinks.ESCAPE_SEQ.put('p', WrapFileLinks.FILE_PATH); @@ -110,11 +98,68 @@ public class WrapFileLinks extends AbstractParamLayoutFormatter { WrapFileLinks.ESCAPE_SEQ.put('d', WrapFileLinks.FILE_DESCRIPTION); } + private final Map replacements = new HashMap<>(); + private final FileLinkPreferences prefs; + private String fileType; + private List format; + public WrapFileLinks(FileLinkPreferences fileLinkPreferences) { this.prefs = fileLinkPreferences; } + /** + * Parse a format string and return a list of FormatEntry objects. The format + * string is basically marked up with "\i" marking that the iteration number should + * be inserted, and with "\p" marking that the file path of the current iteration + * should be inserted, plus additional markers. + * + * @param format The marked-up string. + * @return the resulting format entries. + */ + private static List parseFormatString(String format) { + List l = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + boolean escaped = false; + for (int i = 0; i < format.length(); i++) { + char c = format.charAt(i); + if (escaped) { + escaped = false; // we know we'll be out of escape mode after this + // Check if this escape sequence is meaningful: + if (c == '\\') { + // Escaped backslash: means that we add a backslash: + sb.append('\\'); + } else if (WrapFileLinks.ESCAPE_SEQ.containsKey(c)) { + // Ok, we have the code. Add the previous string (if any) and + // the entry indicated by the escape sequence: + if (sb.length() > 0) { + l.add(new FormatEntry(sb.toString())); + // Clear the buffer: + sb = new StringBuilder(); + } + l.add(new FormatEntry(WrapFileLinks.ESCAPE_SEQ.get(c))); + } else { + // Unknown escape sequence. + sb.append('\\'); + sb.append(c); + } + } else { + // Check if we are at the start of an escape sequence: + if (c == '\\') { + escaped = true; + } else { + sb.append(c); + } + } + } + // Finished scanning the string. If we collected text at the end, add an entry for it: + if (sb.length() > 0) { + l.add(new FormatEntry(sb.toString())); + } + + return l; + } + @Override public void setArgument(String arg) { List parts = AbstractParamLayoutFormatter.parseArgument(arg); @@ -138,10 +183,10 @@ public String format(String field) { StringBuilder sb = new StringBuilder(); // Build the list containing the links: - List fileList = FileField.parse(field); + List fileList = FileFieldParser.parse(field); int piv = 1; // counter for relevant iterations - for (ParsedFileField flEntry : fileList) { + for (LinkedFile flEntry : fileList) { // Use this entry if we don't discriminate on types, or if the type fits: if ((fileType == null) || flEntry.getFileType().equalsIgnoreCase(fileType)) { @@ -165,24 +210,11 @@ public String format(String field) { dirs = prefs.getFileDirForDatabase(); } - Optional f = FileUtil.expandFilename(flEntry.getLink(), dirs); - - /* - * Stumbled over this while investigating - * - * https://sourceforge.net/tracker/index.php?func=detail&aid=1469903&group_id=92314&atid=600306 - */ - if (f.isPresent()) { - try { - sb.append(replaceStrings(f.get().getCanonicalPath())); - } catch (IOException ex) { - LOGGER.warn("Problem getting path", ex); - sb.append(replaceStrings(f.get().getPath())); - } - } else { - sb.append(replaceStrings(flEntry.getLink())); - } + String pathString = flEntry.findIn(dirs) + .map(path -> path.toAbsolutePath().toString()) + .orElse(flEntry.getLink()); + sb.append(replaceStrings(pathString)); break; case RELATIVE_FILE_PATH: @@ -195,7 +227,7 @@ public String format(String field) { break; case FILE_EXTENSION: - FileUtil.getFileExtension(flEntry.getLink()) + FileHelper.getFileExtension(flEntry.getLink()) .ifPresent(extension -> sb.append(replaceStrings(extension))); break; case FILE_TYPE: @@ -226,60 +258,6 @@ private String replaceStrings(String text) { } - - /** - * Parse a format string and return a list of FormatEntry objects. The format - * string is basically marked up with "\i" marking that the iteration number should - * be inserted, and with "\p" marking that the file path of the current iteration - * should be inserted, plus additional markers. - * - * @param format The marked-up string. - * @return the resulting format entries. - */ - private static List parseFormatString(String format) { - List l = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - boolean escaped = false; - for (int i = 0; i < format.length(); i++) { - char c = format.charAt(i); - if (escaped) { - escaped = false; // we know we'll be out of escape mode after this - // Check if this escape sequence is meaningful: - if (c == '\\') { - // Escaped backslash: means that we add a backslash: - sb.append('\\'); - } else if (WrapFileLinks.ESCAPE_SEQ.containsKey(c)) { - // Ok, we have the code. Add the previous string (if any) and - // the entry indicated by the escape sequence: - if (sb.length() > 0) { - l.add(new FormatEntry(sb.toString())); - // Clear the buffer: - sb = new StringBuilder(); - } - l.add(new FormatEntry(WrapFileLinks.ESCAPE_SEQ.get(c))); - } else { - // Unknown escape sequence. - sb.append('\\'); - sb.append(c); - } - } else { - // Check if we are at the start of an escape sequence: - if (c == '\\') { - escaped = true; - } else { - sb.append(c); - } - } - } - // Finished scanning the string. If we collected text at the end, add an entry for it: - if (sb.length() > 0) { - l.add(new FormatEntry(sb.toString())); - } - - return l; - } - - /** * This class defines the building blocks of a parsed format strings. Each FormatEntry * represents either a literal string or a piece of information pertaining to the file diff --git a/src/main/java/org/jabref/logic/net/URLDownload.java b/src/main/java/org/jabref/logic/net/URLDownload.java index df7658b4933..37582330ec1 100644 --- a/src/main/java/org/jabref/logic/net/URLDownload.java +++ b/src/main/java/org/jabref/logic/net/URLDownload.java @@ -37,6 +37,7 @@ import javax.net.ssl.X509TrustManager; import org.jabref.logic.util.io.FileUtil; +import org.jabref.model.util.FileHelper; import com.mashape.unirest.http.Unirest; import org.apache.commons.logging.Log; @@ -208,7 +209,7 @@ public Path toTemporaryFile() throws IOException { // Take everything after the last '/' as name + extension String fileNameWithExtension = sourcePath.substring(sourcePath.lastIndexOf('/') + 1); String fileName = FileUtil.getFileName(fileNameWithExtension); - String extension = "." + FileUtil.getFileExtension(fileNameWithExtension).orElse("tmp"); + String extension = "." + FileHelper.getFileExtension(fileNameWithExtension).orElse("tmp"); // Create temporary file and download to it Path file = Files.createTempFile(fileName, extension); diff --git a/src/main/java/org/jabref/logic/pdf/EntryAnnotationImporter.java b/src/main/java/org/jabref/logic/pdf/EntryAnnotationImporter.java index 37aff755086..fffcf282a84 100644 --- a/src/main/java/org/jabref/logic/pdf/EntryAnnotationImporter.java +++ b/src/main/java/org/jabref/logic/pdf/EntryAnnotationImporter.java @@ -1,19 +1,13 @@ package org.jabref.logic.pdf; -import java.io.File; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; -import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.pdf.FileAnnotation; import org.jabref.preferences.JabRefPreferences; @@ -37,10 +31,10 @@ public EntryAnnotationImporter(BibEntry entry) { * * @return a list of file parsed files */ - public List getFilteredFileList() { - return FileField.parse(this.entry.getField(FieldName.FILE).get()).stream() - .filter(parsedFileField -> parsedFileField.getLink().toLowerCase(Locale.ROOT).endsWith(".pdf")) - .filter(parsedFileField -> !parsedFileField.getLink().contains("www.")).collect(Collectors.toList()); + private List getFilteredFileList() { + return entry.getFiles().stream() + .filter(parsedFileField -> parsedFileField.getFileType().equalsIgnoreCase("pdf")) + .filter(parsedFileField -> !parsedFileField.isOnlineLink()).collect(Collectors.toList()); } /** @@ -54,10 +48,9 @@ public Map> importAnnotationsFromFiles(BibDatabaseC AnnotationImporter importer = new PdfAnnotationImporter(); //import annotationsOfFiles if the selected files are valid which is checked in getFilteredFileList() - for (ParsedFileField parsedFileField : this.getFilteredFileList()) { - Optional expandedFileName = FileUtil.expandFilename(databaseContext, parsedFileField.getLink(), - JabRefPreferences.getInstance().getFileDirectoryPreferences()); - expandedFileName.ifPresent(file -> annotations.put(file.getName(), importer.importAnnotations(file.toPath()))); + for (LinkedFile linkedFile : this.getFilteredFileList()) { + linkedFile.findIn(databaseContext, JabRefPreferences.getInstance().getFileDirectoryPreferences()) + .ifPresent(file -> annotations.put(file.getFileName().toString(), importer.importAnnotations(file))); } return annotations; } diff --git a/src/main/java/org/jabref/logic/util/io/DatabaseFileLookup.java b/src/main/java/org/jabref/logic/util/io/DatabaseFileLookup.java index 82d2fa04678..47b784515e5 100644 --- a/src/main/java/org/jabref/logic/util/io/DatabaseFileLookup.java +++ b/src/main/java/org/jabref/logic/util/io/DatabaseFileLookup.java @@ -1,19 +1,18 @@ package org.jabref.logic.util.io; import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; import org.jabref.model.metadata.FileDirectoryPreferences; /** @@ -24,14 +23,12 @@ */ public class DatabaseFileLookup { - private final Set fileCache = new HashSet<>(); + private final Set fileCache = new HashSet<>(); private final List possibleFilePaths; /** * Creates an instance by passing a {@link BibDatabase} which will be used for the searches. - * - * @param database A {@link BibDatabase}. */ public DatabaseFileLookup(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) { Objects.requireNonNull(databaseContext); @@ -58,26 +55,17 @@ public DatabaseFileLookup(BibDatabaseContext databaseContext, FileDirectoryPrefe * entry in the database, otherwise false. */ public boolean lookupDatabase(File file) { - return fileCache.contains(file); + return fileCache.contains(file.toPath()); } - private List parseFileField(BibEntry entry) { + private List parseFileField(BibEntry entry) { Objects.requireNonNull(entry); - List entries = FileField.parse(entry.getField(FieldName.FILE).orElse(null)); - - List fileLinks = new ArrayList<>(); - for (ParsedFileField field : entries) { - String link = field.getLink(); - - // Do not query external file links (huge performance leak) - if(link.contains("//")) { - continue; - } - - FileUtil.expandFilename(link, possibleFilePaths).ifPresent(fileLinks::add); - } - - return fileLinks; + return entry.getFiles().stream() + .filter(file -> !file.isOnlineLink()) // Do not query external file links (huge performance leak) + .map(file -> file.findIn(possibleFilePaths)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); } } diff --git a/src/main/java/org/jabref/logic/util/io/FileFinder.java b/src/main/java/org/jabref/logic/util/io/FileFinder.java index 522d39e1407..5e8130e45ec 100644 --- a/src/main/java/org/jabref/logic/util/io/FileFinder.java +++ b/src/main/java/org/jabref/logic/util/io/FileFinder.java @@ -13,6 +13,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jabref.model.util.FileHelper; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -30,7 +32,7 @@ public static Set findFiles(List extensions, List directorie BiPredicate isDirectoryAndContainsExtension = (path, attr) -> !Files.isDirectory(path) - && extensions.contains(FileUtil.getFileExtension(path.toFile()).orElse("")); + && extensions.contains(FileHelper.getFileExtension(path.toFile()).orElse("")); Set result = new HashSet<>(); for (File directory : directories) { diff --git a/src/main/java/org/jabref/logic/util/io/FileUtil.java b/src/main/java/org/jabref/logic/util/io/FileUtil.java index 0d65604ae73..a2867390ffe 100644 --- a/src/main/java/org/jabref/logic/util/io/FileUtil.java +++ b/src/main/java/org/jabref/logic/util/io/FileUtil.java @@ -20,18 +20,15 @@ import java.util.Stack; import java.util.Vector; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; import org.jabref.logic.util.OS; import org.jabref.model.database.BibDatabase; -import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; -import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.model.util.OptionalUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -39,39 +36,11 @@ public class FileUtil { private static final Log LOGGER = LogFactory.getLog(FileUtil.class); - private static final Pattern SLASH = Pattern.compile("/"); - private static final Pattern BACKSLASH = Pattern.compile("\\\\"); - public static final boolean isPosixCompilant = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); private FileUtil() { } - /** - * Returns the extension of a file or Optional.empty() if the file does not have one (no . in name). - * - * @param file - * @return The extension, trimmed and in lowercase. - */ - public static Optional getFileExtension(File file) { - return getFileExtension(file.getName()); - } - - /** - * Returns the extension of a file name or Optional.empty() if the file does not have one (no "." in name). - * - * @param fileName - * @return The extension (without leading dot), trimmed and in lowercase. - */ - public static Optional getFileExtension(String fileName) { - int dotPosition = fileName.lastIndexOf('.'); - if ((dotPosition > 0) && (dotPosition < (fileName.length() - 1))) { - return Optional.of(fileName.substring(dotPosition + 1).trim().toLowerCase(Locale.ROOT)); - } else { - return Optional.empty(); - } - } - /** * Returns the name part of a file name (i.e., everything in front of last "."). */ @@ -199,100 +168,6 @@ public static boolean renameFile(Path fromFile, Path toFile, boolean replaceExis } } - /** - * Converts a relative filename to an absolute one, if necessary. Returns an empty optional if the file does not - * exist.
- *

- * Uses

    - *
  • the default directory associated with the extension of the file
  • - *
  • the standard file directory
  • - *
  • the directory of the BIB file
  • - *
- * - * @param databaseContext The database this file belongs to. - * @param name The filename, may also be a relative path to the file - */ - public static Optional expandFilename(final BibDatabaseContext databaseContext, String name, - FileDirectoryPreferences fileDirectoryPreferences) { - Optional extension = getFileExtension(name); - // Find the default directory for this field type, if any: - List directories = databaseContext.getFileDirectories(extension.orElse(null), fileDirectoryPreferences); - // Include the standard "file" directory: - List fileDir = databaseContext.getFileDirectories(fileDirectoryPreferences); - // Include the directory of the BIB file: - List al = new ArrayList<>(); - for (String dir : directories) { - if (!al.contains(dir)) { - al.add(dir); - } - } - for (String aFileDir : fileDir) { - if (!al.contains(aFileDir)) { - al.add(aFileDir); - } - } - - return expandFilename(name, al); - } - - /** - * Converts a relative filename to an absolute one, if necessary. Returns - * null if the file does not exist. - *

- * Will look in each of the given dirs starting from the beginning and - * returning the first found file to match if any. - */ - public static Optional expandFilename(String name, List directories) { - for (String dir : directories) { - if (dir != null) { - Optional result = expandFilename(name, dir); - if (result.isPresent()) { - return result; - } - } - } - - return Optional.empty(); - } - - /** - * 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, String dir) { - - if ((filename == null) || filename.isEmpty()) { - return Optional.empty(); - } - - String name = filename; - - File file = new File(name); - if (file.exists() || (dir == null)) { - return Optional.of(file); - } - - if (dir.endsWith(OS.FILE_SEPARATOR)) { - name = dir + name; - } else { - name = dir + OS.FILE_SEPARATOR + name; - } - - // fix / and \ problems: - if (OS.WINDOWS) { - name = SLASH.matcher(name).replaceAll("\\\\"); - } else { - name = BACKSLASH.matcher(name).replaceAll("/"); - } - - File fileInDir = new File(name); - if (fileInDir.exists()) { - return Optional.of(fileInDir); - } else { - return Optional.empty(); - } - } - /** * Converts an absolute filename to a relative one, if necessary. * Returns the parameter fileName itself if no shortening is possible @@ -397,21 +272,14 @@ public static Map> findAssociatedFiles(List entri * * @return list of files. May be empty */ - public static List getListOfLinkedFiles(List bes, List fileDirs) { + public static List getListOfLinkedFiles(List bes, List fileDirs) { Objects.requireNonNull(bes); Objects.requireNonNull(fileDirs); - List result = new ArrayList<>(); - for (BibEntry entry : bes) { - entry.getField(FieldName.FILE).ifPresent(fileField -> { - List fileList = FileField.parse(fileField); - for (ParsedFileField file : fileList) { - expandFilename(file.getLink(), fileDirs).ifPresent(result::add); - } - }); - } - - return result; + return bes.stream() + .flatMap(entry -> entry.getFiles().stream()) + .flatMap(file -> OptionalUtil.toStream(file.findIn(fileDirs))) + .collect(Collectors.toList()); } /** @@ -481,9 +349,4 @@ public static List find(String filename, List directories) { } return files; } - - public static Optional toPath(ParsedFileField parsedFileField, BibDatabaseContext database, FileDirectoryPreferences directoryPreferences) { - Optional path = expandFilename(database, parsedFileField.getLink(), directoryPreferences); - return path.map(File::toPath); - } } diff --git a/src/main/java/org/jabref/model/entry/BibEntry.java b/src/main/java/org/jabref/model/entry/BibEntry.java index f86bc470fa1..e5dd14a39ab 100644 --- a/src/main/java/org/jabref/model/entry/BibEntry.java +++ b/src/main/java/org/jabref/model/entry/BibEntry.java @@ -781,9 +781,9 @@ public Optional getLatexFreeField(String name) { } } - public Optional setFiles(List files) { + public Optional setFiles(List files) { Optional oldValue = this.getField(FieldName.FILE); - String newValue = FileField.getStringRepresentation(files); + String newValue = FileFieldWriter.getStringRepresentation(files); if (oldValue.isPresent() && oldValue.get().equals(newValue)) { return Optional.empty(); @@ -792,6 +792,21 @@ public Optional setFiles(List files) { return this.setField(FieldName.FILE, newValue); } + /** + * Gets a list of linked files. + * + * @return the list of linked files, is never null but can be empty + */ + public List getFiles() { + //Extract the path + Optional oldValue = getField(FieldName.FILE); + if (!oldValue.isPresent()) { + return Collections.emptyList(); + } + + return FileFieldParser.parse(oldValue.get()); + } + public void setDate(Date date) { date.getYear().ifPresent(year -> setField(FieldName.YEAR, year.toString())); date.getMonth().ifPresent(this::setMonth); diff --git a/src/main/java/org/jabref/model/entry/FileField.java b/src/main/java/org/jabref/model/entry/FileField.java deleted file mode 100644 index bb9c4c21c20..00000000000 --- a/src/main/java/org/jabref/model/entry/FileField.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.jabref.model.entry; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -public class FileField { - - private FileField() { - } - - public static List parse(String value) { - if ((value == null) || value.trim().isEmpty()) { - return Collections.emptyList(); - } - - List files = new ArrayList<>(); - List entry = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - boolean inXmlChar = false; - boolean escaped = false; - - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - if (!escaped && (c == '\\')) { - escaped = true; - continue; - } - // Check if we are entering an XML special character construct such - // as ",", because we need to know in order to ignore the semicolon. - else if (!escaped && (c == '&') && !inXmlChar) { - sb.append(c); - if ((value.length() > (i + 1)) && (value.charAt(i + 1) == '#')) { - inXmlChar = true; - } - } else if (!escaped && inXmlChar && (c == ';')) { - // Check if we are exiting an XML special character construct: - sb.append(c); - inXmlChar = false; - } else if (!escaped && (c == ':')) { - entry.add(sb.toString()); - sb = new StringBuilder(); - } else if (!escaped && (c == ';') && !inXmlChar) { - entry.add(sb.toString()); - sb = new StringBuilder(); - - files.add(convert(entry)); - } else { - sb.append(c); - } - escaped = false; - } - if (sb.length() > 0) { - entry.add(sb.toString()); - } - - if (!entry.isEmpty()) { - files.add(convert(entry)); - } - - return files; - } - - private static ParsedFileField convert(List entry) { - // ensure list has at least 3 fields - while (entry.size() < 3) { - entry.add(""); - } - ParsedFileField field = new ParsedFileField(entry.get(0), entry.get(1), entry.get(2)); - // link is only mandatory field - if(field.getDescription().isEmpty() && field.getLink().isEmpty() && !field.getFileType().isEmpty()) { - field = new ParsedFileField("", field.getFileType(), ""); - } else if(!field.getDescription().isEmpty() && field.getLink().isEmpty() && field.getFileType().isEmpty()) { - field = new ParsedFileField("", field.getDescription(), ""); - } - entry.clear(); - return field; - } - - public static String getStringRepresentation(List fields) { - String[][] array = new String[fields.size()][]; - int i = 0; - for (ParsedFileField entry : fields) { - array[i] = new String[] {entry.getDescription(), entry.getLink(), entry.getFileType()}; - i++; - } - return encodeStringArray(array); - } - - public static String getStringRepresentation(ParsedFileField field) { - return getStringRepresentation(Collections.singletonList(field)); - } - - /** - * Encodes a two-dimensional String array into a single string, using ':' and - * ';' as separators. The characters ':' and ';' are escaped with '\'. - * @param values The String array. - * @return The encoded String. - */ - public static String encodeStringArray(String[][] values) { - return Arrays.asList(values).stream().map(FileField::encodeStringArray).collect(Collectors.joining(";")); - } - - /** - * Encodes a String array into a single string, using ':' as separator. - * The characters ':' and ';' are escaped with '\'. - * @param entry The String array. - * @return The encoded String. - */ - private static String encodeStringArray(String[] entry) { - return Arrays.asList(entry).stream().map(FileField::quote).collect(Collectors.joining(":")); - } - - public static String quote(String s) { - if (s == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if ((c == ';') || (c == ':') || (c == '\\')) { - sb.append('\\'); - } - sb.append(c); - } - return sb.toString(); - } - -} diff --git a/src/main/java/org/jabref/model/entry/FileFieldParser.java b/src/main/java/org/jabref/model/entry/FileFieldParser.java new file mode 100644 index 00000000000..8f8ab78ebd8 --- /dev/null +++ b/src/main/java/org/jabref/model/entry/FileFieldParser.java @@ -0,0 +1,75 @@ +package org.jabref.model.entry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FileFieldParser { + public static List parse(String value) { + if ((value == null) || value.trim().isEmpty()) { + return Collections.emptyList(); + } + + List files = new ArrayList<>(); + List entry = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + boolean inXmlChar = false; + boolean escaped = false; + + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (!escaped && (c == '\\')) { + escaped = true; + continue; + } + // Check if we are entering an XML special character construct such + // as ",", because we need to know in order to ignore the semicolon. + else if (!escaped && (c == '&') && !inXmlChar) { + sb.append(c); + if ((value.length() > (i + 1)) && (value.charAt(i + 1) == '#')) { + inXmlChar = true; + } + } else if (!escaped && inXmlChar && (c == ';')) { + // Check if we are exiting an XML special character construct: + sb.append(c); + inXmlChar = false; + } else if (!escaped && (c == ':')) { + entry.add(sb.toString()); + sb = new StringBuilder(); + } else if (!escaped && (c == ';') && !inXmlChar) { + entry.add(sb.toString()); + sb = new StringBuilder(); + + files.add(convert(entry)); + } else { + sb.append(c); + } + escaped = false; + } + if (sb.length() > 0) { + entry.add(sb.toString()); + } + + if (!entry.isEmpty()) { + files.add(convert(entry)); + } + + return files; + } + + private static LinkedFile convert(List entry) { + // ensure list has at least 3 fields + while (entry.size() < 3) { + entry.add(""); + } + LinkedFile field = new LinkedFile(entry.get(0), entry.get(1), entry.get(2)); + // link is only mandatory field + if(field.getDescription().isEmpty() && field.getLink().isEmpty() && !field.getFileType().isEmpty()) { + field = new LinkedFile("", field.getFileType(), ""); + } else if(!field.getDescription().isEmpty() && field.getLink().isEmpty() && field.getFileType().isEmpty()) { + field = new LinkedFile("", field.getDescription(), ""); + } + entry.clear(); + return field; + } +} diff --git a/src/main/java/org/jabref/model/entry/FileFieldWriter.java b/src/main/java/org/jabref/model/entry/FileFieldWriter.java new file mode 100644 index 00000000000..e0fc47e2db5 --- /dev/null +++ b/src/main/java/org/jabref/model/entry/FileFieldWriter.java @@ -0,0 +1,66 @@ +package org.jabref.model.entry; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class FileFieldWriter { + + private FileFieldWriter() { + } + + public static String getStringRepresentation(List fields) { + String[][] array = new String[fields.size()][]; + int i = 0; + for (LinkedFile entry : fields) { + array[i] = new String[] {entry.getDescription(), entry.getLink(), entry.getFileType()}; + i++; + } + return encodeStringArray(array); + } + + public static String getStringRepresentation(LinkedFile field) { + return getStringRepresentation(Collections.singletonList(field)); + } + + /** + * Encodes a two-dimensional String array into a single string, using ':' and + * ';' as separators. The characters ':' and ';' are escaped with '\'. + * @param values The String array. + * @return The encoded String. + */ + public static String encodeStringArray(String[][] values) { + return Arrays.stream(values) + .map(FileFieldWriter::encodeStringArray) + .collect(Collectors.joining(";")); + } + + /** + * Encodes a String array into a single string, using ':' as separator. + * The characters ':' and ';' are escaped with '\'. + * @param entry The String array. + * @return The encoded String. + */ + private static String encodeStringArray(String[] entry) { + return Arrays.stream(entry) + .map(FileFieldWriter::quote) + .collect(Collectors.joining(":")); + } + + public static String quote(String s) { + if (s == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if ((c == ';') || (c == ':') || (c == '\\')) { + sb.append('\\'); + } + sb.append(c); + } + return sb.toString(); + } + +} diff --git a/src/main/java/org/jabref/model/entry/ParsedFileField.java b/src/main/java/org/jabref/model/entry/LinkedFile.java similarity index 52% rename from src/main/java/org/jabref/model/entry/ParsedFileField.java rename to src/main/java/org/jabref/model/entry/LinkedFile.java index e20a816d8d3..f78b0f7baff 100644 --- a/src/main/java/org/jabref/model/entry/ParsedFileField.java +++ b/src/main/java/org/jabref/model/entry/LinkedFile.java @@ -1,23 +1,34 @@ package org.jabref.model.entry; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; import java.util.Objects; +import java.util.Optional; -public class ParsedFileField { +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.model.util.FileHelper; - private static final ParsedFileField NULL_OBJECT = new ParsedFileField("", "", ""); +/** + * Represents the link to an external file (e.g. associated PDF file). + */ +public class LinkedFile { + + private static final LinkedFile NULL_OBJECT = new LinkedFile("", "", ""); private final String description; private final String link; private final String fileType; - public ParsedFileField(String description, String link, String fileType) { + public LinkedFile(String description, String link, String fileType) { this.description = Objects.requireNonNull(description); this.link = Objects.requireNonNull(link); this.fileType = Objects.requireNonNull(fileType); } - public ParsedFileField(String description, URL link, String fileType) { + public LinkedFile(String description, URL link, String fileType) { this(description, Objects.requireNonNull(link).toString(), fileType); } @@ -38,9 +49,9 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (o instanceof ParsedFileField) { + if (o instanceof LinkedFile) { - ParsedFileField that = (ParsedFileField) o; + LinkedFile that = (LinkedFile) o; if (!this.description.equals(that.description)) { return false; @@ -70,4 +81,22 @@ public String toString() { public boolean isEmpty() { return NULL_OBJECT.equals(this); } + + public boolean isOnlineLink() { + return link.startsWith("http://") || link.startsWith("https://") || link.contains("www."); + } + + public Optional findIn(List directories) { + Path file = Paths.get(link); + if (file.isAbsolute() || directories.isEmpty()) { + return Optional.of(file); + } else { + return FileHelper.expandFilename(link, directories); + } + } + + public Optional findIn(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) { + List dirs = databaseContext.getFileDirectories(fileDirectoryPreferences); + return findIn(dirs); + } } diff --git a/src/main/java/org/jabref/model/util/FileHelper.java b/src/main/java/org/jabref/model/util/FileHelper.java new file mode 100644 index 00000000000..c4c4425d89a --- /dev/null +++ b/src/main/java/org/jabref/model/util/FileHelper.java @@ -0,0 +1,119 @@ +package org.jabref.model.util; + +import java.io.File; +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.metadata.FileDirectoryPreferences; + +public class FileHelper { + /** + * Returns the extension of a file or Optional.empty() if the file does not have one (no . in name). + * + * @param file + * @return The extension, trimmed and in lowercase. + */ + public static Optional getFileExtension(File file) { + return getFileExtension(file.getName()); + } + + /** + * Returns the extension of a file name or Optional.empty() if the file does not have one (no "." in name). + * + * @param fileName + * @return The extension (without leading dot), trimmed and in lowercase. + */ + public static Optional getFileExtension(String fileName) { + int dotPosition = fileName.lastIndexOf('.'); + if ((dotPosition > 0) && (dotPosition < (fileName.length() - 1))) { + return Optional.of(fileName.substring(dotPosition + 1).trim().toLowerCase(Locale.ROOT)); + } else { + return Optional.empty(); + } + } + + /** + * Converts a relative filename to an absolute one, if necessary. Returns an empty optional if the file does not + * exist.
+ *

+ * Uses

    + *
  • the default directory associated with the extension of the file
  • + *
  • the standard file directory
  • + *
  • the directory of the BIB file
  • + *
+ * + * @param databaseContext The database this file belongs to. + * @param name The filename, may also be a relative path to the file + */ + public static Optional expandFilename(final BibDatabaseContext databaseContext, String name, + FileDirectoryPreferences fileDirectoryPreferences) { + Optional extension = getFileExtension(name); + // Find the default directory for this field type, if any: + List directories = databaseContext.getFileDirectories(extension.orElse(null), fileDirectoryPreferences); + // Include the standard "file" directory: + List fileDir = databaseContext.getFileDirectories(fileDirectoryPreferences); + + 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); + } + + /** + * Converts a relative filename to an absolute one, if necessary. Returns + * null if the file does not exist. + *

+ * Will look in each of the given dirs starting from the beginning and + * returning the first found file to match if any. + */ + public static Optional expandFilename(String name, List directories) { + for (String dir : directories) { + if (dir != null) { + Optional result = expandFilename(name, dir); + if (result.isPresent()) { + return result; + } + } + } + + return Optional.empty(); + } + + /** + * 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, String directoryName) { + Objects.requireNonNull(filename); + Objects.requireNonNull(directoryName); + + Path file = Paths.get(filename); + if (Files.exists(file)) { + return Optional.of(file); + } + + Path directory = Paths.get(directoryName); + Path resolvedFile = directory.resolve(file); + if (Files.exists(resolvedFile)) { + return Optional.of(resolvedFile); + } else { + return Optional.empty(); + } + } +} diff --git a/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java b/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java index 7747efced6c..aa3d6408122 100644 --- a/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java +++ b/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java @@ -25,8 +25,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldWriter; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; import org.jabref.model.metadata.MetaData; import org.jabref.preferences.JabRefPreferences; @@ -98,8 +98,8 @@ public void cleanupDoesNothingByDefault() throws IOException { entry.setField("title", "hallo units 1 A case AlGaAs and latex $\\alpha$$\\beta$"); entry.setField("abstract", "Réflexions"); File tempFile = bibFolder.newFile(); - ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", tempFile.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); List changes = worker.cleanup(emptyPreset, entry); Assert.assertEquals(Collections.emptyList(), changes); @@ -225,12 +225,12 @@ public void cleanupMoveFilesMovesFileFromSubfolder() throws IOException { File tempFile = new File(subfolder, "test.pdf"); tempFile.createNewFile(); BibEntry entry = new BibEntry(); - ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", tempFile.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); worker.cleanup(preset, entry); - ParsedFileField newFileField = new ParsedFileField("", tempFile.getName(), ""); - Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", tempFile.getName(), ""); + Assert.assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @Test @@ -239,12 +239,12 @@ public void cleanupRelativePathsConvertAbsoluteToRelativePath() throws IOExcepti File tempFile = bibFolder.newFile(); BibEntry entry = new BibEntry(); - ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", tempFile.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); worker.cleanup(preset, entry); - ParsedFileField newFileField = new ParsedFileField("", tempFile.getName(), ""); - Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", tempFile.getName(), ""); + Assert.assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @Test @@ -254,12 +254,12 @@ public void cleanupRenamePdfRenamesRelativeFile() throws IOException { File tempFile = bibFolder.newFile(); BibEntry entry = new BibEntry(); entry.setCiteKey("Toot"); - ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", tempFile.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); worker.cleanup(preset, entry); - ParsedFileField newFileField = new ParsedFileField("", "Toot.tmp", ""); - Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", "Toot.tmp", ""); + Assert.assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @Test diff --git a/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java index 4b17fd54486..7ac3dd51caa 100644 --- a/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java @@ -12,8 +12,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldWriter; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; import org.jabref.model.metadata.MetaData; @@ -61,8 +61,8 @@ public void movesFileFromSubfolder() throws IOException { assertTrue(fileBefore.createNewFile()); assertTrue(new File(subfolder, "test.pdf").exists()); - ParsedFileField fileField = new ParsedFileField("", fileBefore.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); cleanup = new MoveFilesCleanup(databaseContext, "", fileDirPrefs, mock(LayoutFormatterPreferences.class)); cleanup.cleanup(entry); @@ -71,7 +71,7 @@ public void movesFileFromSubfolder() throws IOException { File fileAfter = new File(pdfFolder, "test.pdf"); assertTrue(fileAfter.exists()); - assertEquals(Optional.of(FileField.getStringRepresentation(new ParsedFileField("", fileAfter.getName(), ""))), + assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(new LinkedFile("", fileAfter.getName(), ""))), entry.getField("file")); } @@ -82,9 +82,9 @@ public void movesFileFromSubfolderMultiple() throws IOException { assertTrue(fileBefore.createNewFile()); assertTrue(fileBefore.exists()); - ParsedFileField fileField = new ParsedFileField("", fileBefore.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation( - Arrays.asList(new ParsedFileField("", "", ""), fileField, new ParsedFileField("", "", "")))); + LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation( + Arrays.asList(new LinkedFile("", "", ""), fileField, new LinkedFile("", "", "")))); cleanup = new MoveFilesCleanup(databaseContext, "", fileDirPrefs, mock(LayoutFormatterPreferences.class)); @@ -95,8 +95,8 @@ public void movesFileFromSubfolderMultiple() throws IOException { assertTrue(fileAfter.exists()); assertEquals( - Optional.of(FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("", "", ""), - new ParsedFileField("", fileAfter.getName(), ""), new ParsedFileField("", "", "")))), + Optional.of(FileFieldWriter.getStringRepresentation(Arrays.asList(new LinkedFile("", "", ""), + new LinkedFile("", fileAfter.getName(), ""), new LinkedFile("", "", "")))), entry.getField("file")); } @@ -108,8 +108,8 @@ public void movesFileFromSubfolderWithFileDirPattern() throws IOException { assertTrue(fileBefore.createNewFile()); assertTrue(new File(subfolder, "test.pdf").exists()); - ParsedFileField fileField = new ParsedFileField("", fileBefore.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", fileBefore.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); cleanup = new MoveFilesCleanup(databaseContext, "\\EntryType", fileDirPrefs, mock(LayoutFormatterPreferences.class)); @@ -121,7 +121,7 @@ public void movesFileFromSubfolderWithFileDirPattern() throws IOException { assertTrue(Files.exists(after)); assertEquals(Optional - .of(FileField.getStringRepresentation(new ParsedFileField("", relativefileDir.toString(), ""))), + .of(FileFieldWriter.getStringRepresentation(new LinkedFile("", relativefileDir.toString(), ""))), entry.getField("file")); } } diff --git a/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java index 1d63483f627..31a3d41f867 100644 --- a/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java @@ -11,8 +11,8 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FileField; -import org.jabref.model.entry.ParsedFileField; +import org.jabref.model.entry.FileFieldWriter; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; import org.jabref.model.metadata.MetaData; import org.jabref.preferences.JabRefPreferences; @@ -57,15 +57,15 @@ public void setUp() throws Exception { public void cleanupRenamePdfRenamesFileEvenIfOnlyDifferenceIsCase() throws IOException { String fileNamePattern = "\\bibtexkey"; File tempFile = testFolder.newFile("toot.tmp"); - ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", tempFile.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, mock(LayoutFormatterPreferences.class), fileDirPrefs); cleanup.cleanup(entry); - ParsedFileField newFileField = new ParsedFileField("", "Toot.tmp", ""); - assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", "Toot.tmp", ""); + assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @Test @@ -74,16 +74,16 @@ public void cleanupRenamePdfRenamesWithMultipleFiles() throws IOException { File tempFile = testFolder.newFile("Toot.tmp"); entry.setField("title", "test title"); - entry.setField("file", FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("", "", ""), - new ParsedFileField("", tempFile.getAbsolutePath(), ""), new ParsedFileField("", "", "")))); + entry.setField("file", FileFieldWriter.getStringRepresentation(Arrays.asList(new LinkedFile("", "", ""), + new LinkedFile("", tempFile.getAbsolutePath(), ""), new LinkedFile("", "", "")))); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, mock(LayoutFormatterPreferences.class), fileDirPrefs); cleanup.cleanup(entry); assertEquals( - Optional.of(FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("", "", ""), - new ParsedFileField("", "Toot - test title.tmp", ""), new ParsedFileField("", "", "")))), + Optional.of(FileFieldWriter.getStringRepresentation(Arrays.asList(new LinkedFile("", "", ""), + new LinkedFile("", "Toot - test title.tmp", ""), new LinkedFile("", "", "")))), entry.getField("file")); } @@ -92,24 +92,24 @@ public void cleanupRenamePdfRenamesFileStartingWithBibtexKey() throws IOExceptio String fileNamePattern = "\\bibtexkey - \\title"; File tempFile = testFolder.newFile("Toot.tmp"); - ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), ""); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", tempFile.getAbsolutePath(), ""); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, mock(LayoutFormatterPreferences.class), fileDirPrefs); cleanup.cleanup(entry); - ParsedFileField newFileField = new ParsedFileField("", "Toot - test title.tmp", ""); - assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", "Toot - test title.tmp", ""); + assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @Test public void cleanupRenamePdfRenamesFileInSameFolder() throws IOException { String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}"; testFolder.newFile("Toot.pdf"); - ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF"); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", "Toot.pdf", "PDF"); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, @@ -117,16 +117,16 @@ public void cleanupRenamePdfRenamesFileInSameFolder() throws IOException { fileDirPrefs); cleanup.cleanup(entry); - ParsedFileField newFileField = new ParsedFileField("", "Toot - test title.pdf", "PDF"); - assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", "Toot - test title.pdf", "PDF"); + assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @Test public void cleanupSingleField() throws IOException { String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}"; testFolder.newFile("Toot.pdf"); - ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF"); - entry.setField("file", FileField.getStringRepresentation(fileField)); + LinkedFile fileField = new LinkedFile("", "Toot.pdf", "PDF"); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)), @@ -134,8 +134,8 @@ public void cleanupSingleField() throws IOException { cleanup.cleanup(entry); - ParsedFileField newFileField = new ParsedFileField("", "Toot - test title.pdf", "PDF"); - assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file")); + LinkedFile newFileField = new LinkedFile("", "Toot - test title.pdf", "PDF"); + assertEquals(Optional.of(FileFieldWriter.getStringRepresentation(newFileField)), entry.getField("file")); } @@ -143,11 +143,11 @@ public void cleanupSingleField() throws IOException { public void cleanupGetTargetFilename() throws IOException { String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}"; testFolder.newFile("Toot.pdf"); - ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF"); + LinkedFile fileField = new LinkedFile("", "Toot.pdf", "PDF"); RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)), fileDirPrefs); - entry.setField("file", FileField.getStringRepresentation(fileField)); + entry.setField("file", FileFieldWriter.getStringRepresentation(fileField)); entry.setField("title", "test title"); assertEquals("Toot - test title.pdf", cleanup.getTargetFileName(fileField, entry)); diff --git a/src/test/java/org/jabref/logic/util/io/FileUtilTest.java b/src/test/java/org/jabref/logic/util/io/FileUtilTest.java index 307271fdaca..2739f3c1804 100644 --- a/src/test/java/org/jabref/logic/util/io/FileUtilTest.java +++ b/src/test/java/org/jabref/logic/util/io/FileUtilTest.java @@ -14,6 +14,7 @@ import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.model.entry.BibEntry; +import org.jabref.model.util.FileHelper; import org.jabref.preferences.JabRefPreferences; import org.junit.Before; @@ -125,52 +126,52 @@ public void testGetLinkedFileNameGetDefaultIfEmptyFieldNoKey() { @Test public void testGetFileExtensionSimpleFile() { - assertEquals("pdf", FileUtil.getFileExtension(new File("test.pdf")).get()); + assertEquals("pdf", FileHelper.getFileExtension(new File("test.pdf")).get()); } @Test public void testGetFileExtensionLowerCaseAndTrimmingFile() { - assertEquals("pdf", FileUtil.getFileExtension(new File("test.PdF ")).get()); + assertEquals("pdf", FileHelper.getFileExtension(new File("test.PdF ")).get()); } @Test public void testGetFileExtensionMultipleDotsFile() { - assertEquals("pdf", FileUtil.getFileExtension(new File("te.st.PdF ")).get()); + assertEquals("pdf", FileHelper.getFileExtension(new File("te.st.PdF ")).get()); } @Test public void testGetFileExtensionNoExtensionFile() { - assertFalse(FileUtil.getFileExtension(new File("JustTextNotASingleDot")).isPresent()); + assertFalse(FileHelper.getFileExtension(new File("JustTextNotASingleDot")).isPresent()); } @Test public void testGetFileExtensionNoExtension2File() { - assertFalse(FileUtil.getFileExtension(new File(".StartsWithADotIsNotAnExtension")).isPresent()); + assertFalse(FileHelper.getFileExtension(new File(".StartsWithADotIsNotAnExtension")).isPresent()); } @Test public void getFileExtensionWithSimpleString() { - assertEquals("pdf", FileUtil.getFileExtension("test.pdf").get()); + assertEquals("pdf", FileHelper.getFileExtension("test.pdf").get()); } @Test public void getFileExtensionTrimsAndReturnsInLowercase() { - assertEquals("pdf", FileUtil.getFileExtension("test.PdF ").get()); + assertEquals("pdf", FileHelper.getFileExtension("test.PdF ").get()); } @Test public void getFileExtensionWithMultipleDotsString() { - assertEquals("pdf", FileUtil.getFileExtension("te.st.PdF ").get()); + assertEquals("pdf", FileHelper.getFileExtension("te.st.PdF ").get()); } @Test public void getFileExtensionWithNoDotReturnsEmptyExtension() { - assertEquals(Optional.empty(), FileUtil.getFileExtension("JustTextNotASingleDot")); + assertEquals(Optional.empty(), FileHelper.getFileExtension("JustTextNotASingleDot")); } @Test public void getFileExtensionWithDotAtStartReturnsEmptyExtension() { - assertEquals(Optional.empty(), FileUtil.getFileExtension(".StartsWithADotIsNotAnExtension")); + assertEquals(Optional.empty(), FileHelper.getFileExtension(".StartsWithADotIsNotAnExtension")); } @Test diff --git a/src/test/java/org/jabref/model/entry/FileFieldTest.java b/src/test/java/org/jabref/model/entry/FileFieldTest.java deleted file mode 100644 index f65d7cf4ec4..00000000000 --- a/src/test/java/org/jabref/model/entry/FileFieldTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.jabref.model.entry; - -import java.util.Arrays; -import java.util.Collections; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -public class FileFieldTest { - - @Test - public void emptyListForEmptyInput() { - String emptyInput = ""; - String nullInput = null; - - assertEquals(Collections.emptyList(), FileField.parse(emptyInput)); - assertEquals(Collections.emptyList(), FileField.parse(nullInput)); - } - - @Test - public void parseCorrectInput() { - String input = "Desc:File.PDF:PDF"; - - assertEquals(Collections.singletonList(new ParsedFileField("Desc", "File.PDF", "PDF")), FileField.parse(input)); - } - - @Test - public void ingoreMissingDescription() { - String input = ":wei2005ahp.pdf:PDF"; - - assertEquals(Collections.singletonList(new ParsedFileField("", "wei2005ahp.pdf", "PDF")), FileField.parse(input)); - } - - @Test - public void interpreteLinkAsOnlyMandatoryField() { - String single = "wei2005ahp.pdf"; - String multiple = "wei2005ahp.pdf;other.pdf"; - - assertEquals(Collections.singletonList(new ParsedFileField("", "wei2005ahp.pdf", "")), FileField.parse(single)); - assertEquals(Arrays.asList(new ParsedFileField("", "wei2005ahp.pdf", ""), new ParsedFileField("", "other.pdf", "")), FileField.parse(multiple)); - } - - @Test - public void escapedCharactersInDescription() { - String input = "test\\:\\;:wei2005ahp.pdf:PDF"; - - assertEquals(Collections.singletonList(new ParsedFileField("test:;", "wei2005ahp.pdf", "PDF")), FileField.parse(input)); - } - - @Test - public void handleXmlCharacters() { - String input = "test,\\;st\\:\\;:wei2005ahp.pdf:PDF"; - - assertEquals(Collections.singletonList(new ParsedFileField("test,st:;", "wei2005ahp.pdf", "PDF")), FileField.parse(input)); - } - - @Test - public void handleEscapedFilePath() { - String input = "desc:C\\:\\\\test.pdf:PDF"; - - assertEquals(Collections.singletonList(new ParsedFileField("desc", "C:\\test.pdf", "PDF")), FileField.parse(input)); - } - - @Test - public void subsetOfFieldsResultsInFileLink() { - String descOnly = "file.pdf::"; - String fileOnly = ":file.pdf"; - String typeOnly = "::file.pdf"; - - assertEquals(Collections.singletonList(new ParsedFileField("", "file.pdf", "")), FileField.parse(descOnly)); - assertEquals(Collections.singletonList(new ParsedFileField("", "file.pdf", "")), FileField.parse(fileOnly)); - assertEquals(Collections.singletonList(new ParsedFileField("", "file.pdf", "")), FileField.parse(typeOnly)); - } - - @Test - public void tooManySeparators() { - String input = "desc:file.pdf:PDF:asdf"; - - assertEquals(Collections.singletonList(new ParsedFileField("desc", "file.pdf", "PDF")), FileField.parse(input)); - } - - @Test - public void testQuoteStandard() { - assertEquals("a", FileField.quote("a")); - } - - @Test - public void testQuoteAllCharacters() { - assertEquals("a\\:\\;\\\\", FileField.quote("a:;\\")); - } - - @Test - public void testQuoteEmpty() { - assertEquals("", FileField.quote("")); - } - - @Test - public void testQuoteNull() { - assertNull(FileField.quote(null)); - } - -} diff --git a/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java b/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java new file mode 100644 index 00000000000..b507b7bebae --- /dev/null +++ b/src/test/java/org/jabref/model/entry/FileFieldWriterTest.java @@ -0,0 +1,111 @@ +package org.jabref.model.entry; + +import java.util.Arrays; +import java.util.Collections; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class FileFieldWriterTest { + + @Test + public void emptyListForEmptyInput() { + String emptyInput = ""; + String nullInput = null; + + assertEquals(Collections.emptyList(), FileFieldParser.parse(emptyInput)); + assertEquals(Collections.emptyList(), FileFieldParser.parse(nullInput)); + } + + @Test + public void parseCorrectInput() { + String input = "Desc:File.PDF:PDF"; + + assertEquals(Collections.singletonList(new LinkedFile("Desc", "File.PDF", "PDF")), FileFieldParser.parse(input)); + } + + @Test + public void ingoreMissingDescription() { + String input = ":wei2005ahp.pdf:PDF"; + + assertEquals(Collections.singletonList(new LinkedFile("", "wei2005ahp.pdf", "PDF")), FileFieldParser.parse(input)); + } + + @Test + public void interpreteLinkAsOnlyMandatoryField() { + String single = "wei2005ahp.pdf"; + String multiple = "wei2005ahp.pdf;other.pdf"; + + assertEquals(Collections.singletonList(new LinkedFile("", "wei2005ahp.pdf", "")), FileFieldParser.parse(single)); + assertEquals(Arrays.asList(new LinkedFile("", "wei2005ahp.pdf", ""), new LinkedFile("", "other.pdf", "")), FileFieldParser.parse(multiple)); + } + + @Test + public void escapedCharactersInDescription() { + String input = "test\\:\\;:wei2005ahp.pdf:PDF"; + + assertEquals(Collections.singletonList(new LinkedFile("test:;", "wei2005ahp.pdf", "PDF")), FileFieldParser.parse(input)); + } + + @Test + public void handleXmlCharacters() { + String input = "test,\\;st\\:\\;:wei2005ahp.pdf:PDF"; + + assertEquals(Collections.singletonList(new LinkedFile("test,st:;", "wei2005ahp.pdf", "PDF")), FileFieldParser.parse(input)); + } + + @Test + public void handleEscapedFilePath() { + String input = "desc:C\\:\\\\test.pdf:PDF"; + + assertEquals(Collections.singletonList(new LinkedFile("desc", "C:\\test.pdf", "PDF")), FileFieldParser.parse(input)); + } + + @Test + public void subsetOfFieldsResultsInFileLink() { + String descOnly = "file.pdf::"; + String fileOnly = ":file.pdf"; + String typeOnly = "::file.pdf"; + + assertEquals(Collections.singletonList(new LinkedFile("", "file.pdf", "")), FileFieldParser.parse(descOnly)); + assertEquals(Collections.singletonList(new LinkedFile("", "file.pdf", "")), FileFieldParser.parse(fileOnly)); + assertEquals(Collections.singletonList(new LinkedFile("", "file.pdf", "")), FileFieldParser.parse(typeOnly)); + } + + @Test + public void tooManySeparators() { + String input = "desc:file.pdf:PDF:asdf"; + + assertEquals(Collections.singletonList(new LinkedFile("desc", "file.pdf", "PDF")), FileFieldParser.parse(input)); + } + + @Test + public void testQuoteStandard() { + assertEquals("a", FileFieldWriter.quote("a")); + } + + @Test + public void testQuoteAllCharacters() { + assertEquals("a\\:\\;\\\\", FileFieldWriter.quote("a:;\\")); + } + + @Test + public void testQuoteEmpty() { + assertEquals("", FileFieldWriter.quote("")); + } + + @Test + public void testQuoteNull() { + assertNull(FileFieldWriter.quote(null)); + } + + @Test + public void testEncodeStringArray() { + assertEquals("a:b;c:d", FileFieldWriter.encodeStringArray(new String[][]{{"a", "b"}, {"c", "d"}})); + assertEquals("a:;c:d", FileFieldWriter.encodeStringArray(new String[][]{{"a", ""}, {"c", "d"}})); + assertEquals("a:" + null + ";c:d", FileFieldWriter.encodeStringArray(new String[][]{{"a", null}, {"c", "d"}})); + assertEquals("a:\\:b;c\\;:d", FileFieldWriter.encodeStringArray(new String[][]{{"a", ":b"}, {"c;", "d"}})); + } +} diff --git a/src/test/java/org/jabref/model/strings/StringUtilTest.java b/src/test/java/org/jabref/model/strings/StringUtilTest.java index 0ccd75b647b..4a870394242 100644 --- a/src/test/java/org/jabref/model/strings/StringUtilTest.java +++ b/src/test/java/org/jabref/model/strings/StringUtilTest.java @@ -2,8 +2,6 @@ import java.util.Optional; -import org.jabref.model.entry.FileField; - import org.junit.Test; import static org.junit.Assert.assertArrayEquals; @@ -44,15 +42,6 @@ public void testQuoteMoreComplicated() { assertEquals("a::b:%c:;", StringUtil.quote("a:b%c;", "%;", ':')); } - private static final String[][] STRING_ARRAY_1 = {{"a", "b"}, {"c", "d"}}; - private static final String ENCODED_STRING_ARRAY_1 = "a:b;c:d"; - private static final String[][] STRING_ARRAY_2_WITH_NULL = {{"a", null}, {"c", "d"}}; - private static final String ENCODED_STRING_ARRAY_2_WITH_NULL = "a:" + null + ";c:d"; - private static final String[][] STRING_ARRAY_2 = {{"a", ""}, {"c", "d"}}; - private static final String ENCODED_STRING_ARRAY_2 = "a:;c:d"; - private static final String[][] STRING_ARRAY_3 = {{"a", ":b"}, {"c;", "d"}}; - private static final String ENCODED_STRING_ARRAY_3 = "a:\\:b;c\\;:d"; - @Test public void testUnifyLineBreaks() { @@ -167,21 +156,13 @@ public void testWrap() { StringUtil.wrap("aaaaa\r\nbbbbb\r\nccccc", 12, newline)); } - @Test - public void testEncodeStringArray() { - assertEquals(ENCODED_STRING_ARRAY_1, FileField.encodeStringArray(STRING_ARRAY_1)); - assertEquals(ENCODED_STRING_ARRAY_2, FileField.encodeStringArray(STRING_ARRAY_2)); - assertEquals(ENCODED_STRING_ARRAY_2_WITH_NULL, FileField.encodeStringArray(STRING_ARRAY_2_WITH_NULL)); - assertEquals(ENCODED_STRING_ARRAY_3, FileField.encodeStringArray(STRING_ARRAY_3)); - } - @Test public void testDecodeStringDoubleArray() { - assertArrayEquals(STRING_ARRAY_1, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_1)); - assertArrayEquals(STRING_ARRAY_2, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_2)); + assertArrayEquals(new String[][]{{"a", "b"}, {"c", "d"}}, StringUtil.decodeStringDoubleArray("a:b;c:d")); + assertArrayEquals(new String[][]{{"a", ""}, {"c", "d"}}, StringUtil.decodeStringDoubleArray("a:;c:d")); // arrays first differed at element [0][1]; expected: null but was: java.lang.String // assertArrayEquals(stringArray2res, StringUtil.decodeStringDoubleArray(encStringArray2)); - assertArrayEquals(STRING_ARRAY_3, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_3)); + assertArrayEquals(new String[][]{{"a", ":b"}, {"c;", "d"}}, StringUtil.decodeStringDoubleArray("a:\\:b;c\\;:d")); } @Test