diff --git a/CHANGELOG.md b/CHANGELOG.md index f711e4e8841..635a898e83a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,8 +114,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where special characters where removed from non label key generation pattern parts [#4767](https://github.com/JabRef/jabref/issues/4767) - We fixed an issue where the RIS import would overwite the article date with the value of the acessed date [#4816](https://github.com/JabRef/jabref/issues/4816) - We fixed an issue where an NullPointer exception was thrown when a referenced entry in an Open/Libre Office document was no longer present in the library. Now an error message with the reference marker of the missing entry is shown. [#4932](https://github.com/JabRef/jabref/issues/4932) - - +- We fixed an issue where a database exception related to a missing timezone was too big. [#4827](https://github.com/JabRef/jabref/issues/4827) ### Removed - The feature to "mark entries" was removed and merged with the groups functionality. For migration, a group is created for every value of the `__markedentry` field and the entry is added to this group. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64d5105299b..24c25a05b9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,15 @@ After reading through this guide, check out some good first issues to contribute to by clicking here: [Good First Issues](https://github.com/JabRef/jabref/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) ## Understanding the basics -We welcome contributions to JabRef and encourage to create a fork, clone, **create a new branch** (such as `fix-for-issue-121`), **work on the new branch — not master**, and create a pull request. -Be sure to create a **separate branch** for each improvement you implement. -Take a look at GitHub's excellent overview on the [GitHub flow](https://guides.github.com/introduction/flow/index.html) and their [pull request help documentation](https://help.github.com/articles/about-pull-requests/) for a detailed explanation and the explanation of [Feature Branch Workflow](https://de.atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow) for the idea behind this kind of development. - -We also have [code howtos](https://github.com/JabRef/jabref/wiki/Code-Howtos) and [guidelines for setting up a local workspace](https://github.com/JabRef/jabref/wiki/Guidelines-for-setting-up-a-local-workspace). - -In case you have any question, do not hesitate to write one of our [JabRef developers](https://github.com/orgs/JabRef/teams/developers) an email. -We should also be online at [gitter](https://gitter.im/JabRef/jabref). +We welcome contributions to JabRef and encourage you to follow the GitHub workflow specified below. If you are not familiar with this type of workflow, take a look at GitHub's excellent overview on the [GitHub flow](https://guides.github.com/introduction/flow/index.html) and the explanation of [Feature Branch Workflow](https://atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow) for the idea behind this kind of development. +1. Get the JabRef code on your local machine. Detailed instructions about this step can be found in our [guidelines for setting up a local workspace](https://github.com/JabRef/jabref/wiki/Guidelines-for-setting-up-a-local-workspace). + 1. Fork the JabRef into your GitHub account. + 2. Clone your forked repository on your local machine. +3. **Create a new branch** (such as `fix-for-issue-121`). Be sure to create a **separate branch** for each improvement you implement. +4. Do your work on the **new branch - not the master branch.** Refer to our [code howtos](https://github.com/JabRef/jabref/wiki/Code-Howtos) if you have questions about your implementation. +5. Create a pull request. For an overview of pull requests, take a look at GitHub's [pull request help documentation](https://help.github.com/articles/about-pull-requests/). + +In case you have any questions, do not hesitate to write one of our [JabRef developers](https://github.com/orgs/JabRef/teams/developers) an email. We should also be online at [gitter](https://gitter.im/JabRef/jabref). ## Formal requirements for a pull request diff --git a/README.md b/README.md index cec54b33f74..d0a9efc35f7 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,11 @@ An explanation of donation possibilities and usage of donations is available at > Not a programmer? [Learn how to help.](http://contribute.jabref.org) -Want to be part of a free and open-source project that tens of thousands scientist use every day? -Check out our [issue tracker](https://github.com/JabRef/jabref/issues) to find something to work on. -You are also welcome to contribute new features. -To get your code included into JabRef, just fork JabRef and create a pull request. -For details have a look at our [guidelines for contributing](CONTRIBUTING.md). +Want to be part of a free and open-source project that tens of thousands scientist use every day? Check out the ways you can contribute, below: +- For details on how to contribute, have a look at our [guidelines for contributing](CONTRIBUTING.md). +- You are welcome to contribute new features. To get your code included into JabRef, just [fork](https://help.github.com/en/articles/fork-a-repo) the JabRef repository, make your changes, and create a [pull request](https://help.github.com/en/articles/about-pull-requests). +- To work on existing JabRef issues, check out our [issue tracker](https://github.com/JabRef/jabref/issues). New to open source contributing? Look for issues with the ["good first issue"](https://github.com/JabRef/jabref/labels/good%20first%20issue) label to get started. + We view pull requests as a collaborative process. Submit a pull request early to get feedback from the team on work in progress. We will discuss improvements with you and agree to merge them once the [developers](https://github.com/JabRef/jabref/blob/master/DEVELOPERS) approve. diff --git a/build.gradle b/build.gradle index 3731ef3acbb..fed3e3894da 100644 --- a/build.gradle +++ b/build.gradle @@ -136,9 +136,9 @@ dependencies { compile 'com.jfoenix:jfoenix:8.0.8' // Cannot be updated to 9.*.* until Jabref works with Java 9 - compile 'org.controlsfx:controlsfx:8.40.15-SNAPSHOT' + compile 'org.controlsfx:controlsfx:8.40.16-SNAPSHOT' - compile 'org.jsoup:jsoup:1.11.3' + compile 'org.jsoup:jsoup:1.12.1' compile 'com.mashape.unirest:unirest-java:1.4.9' // >1.8.0-beta is required for java 9 compatibility diff --git a/src/main/java/org/jabref/gui/JabRefDialogService.java b/src/main/java/org/jabref/gui/JabRefDialogService.java index 4ae2146a8b6..cde1170f3e8 100644 --- a/src/main/java/org/jabref/gui/JabRefDialogService.java +++ b/src/main/java/org/jabref/gui/JabRefDialogService.java @@ -165,6 +165,7 @@ public void showErrorDialogAndWait(String title, String content) { @Override public void showErrorDialogAndWait(String message, Throwable exception) { ExceptionDialog exceptionDialog = new ExceptionDialog(exception); + exceptionDialog.getDialogPane().setMaxWidth(mainWindow.getWidth() / 2); exceptionDialog.setHeaderText(message); exceptionDialog.showAndWait(); } diff --git a/src/main/java/org/jabref/gui/externalfiles/FindFullTextAction.java b/src/main/java/org/jabref/gui/externalfiles/FindFullTextAction.java index 72c2bedd70d..d8ac847130e 100644 --- a/src/main/java/org/jabref/gui/externalfiles/FindFullTextAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/FindFullTextAction.java @@ -13,6 +13,7 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.fieldeditors.LinkedFileViewModel; import org.jabref.gui.fieldeditors.LinkedFilesEditorViewModel; import org.jabref.gui.util.BackgroundTask; @@ -136,7 +137,7 @@ private void addLinkedFileFromURL(URL url, BibEntry entry, Path targetDirectory) basePanel.getBibDatabaseContext(), Globals.TASK_EXECUTOR, dialogService, - JabRefPreferences.getInstance()); + JabRefPreferences.getInstance(), ExternalFileTypes.getInstance()); try { URLDownload urlDownload = new URLDownload(newLinkedFile.getLink()); @@ -144,7 +145,7 @@ private void addLinkedFileFromURL(URL url, BibEntry entry, Path targetDirectory) downloadTask.onSuccess(destination -> { LinkedFile downloadedFile = LinkedFilesEditorViewModel.fromFile( destination, - basePanel.getBibDatabaseContext().getFileDirectoriesAsPaths(JabRefPreferences.getInstance().getFilePreferences())); + basePanel.getBibDatabaseContext().getFileDirectoriesAsPaths(JabRefPreferences.getInstance().getFilePreferences()), ExternalFileTypes.getInstance()); entry.addFile(downloadedFile); dialogService.notify(Localization.lang("Finished downloading full text document for entry %0.", entry.getCiteKeyOptional().orElse(Localization.lang("undefined")))); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 3fd76b4b379..847847f836e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -66,13 +66,15 @@ public class LinkedFileViewModel extends AbstractViewModel { private final FilePreferences filePreferences; private final XmpPreferences xmpPreferences; private final LinkedFileHandler linkedFileHandler; + private final ExternalFileTypes externalFileTypes; public LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, DialogService dialogService, - JabRefPreferences preferences) { + JabRefPreferences preferences, + ExternalFileTypes externalFileTypes) { this.linkedFile = linkedFile; this.filePreferences = preferences.getFilePreferences(); @@ -81,6 +83,7 @@ public LinkedFileViewModel(LinkedFile linkedFile, this.entry = entry; this.dialogService = dialogService; this.taskExecutor = taskExecutor; + this.externalFileTypes = externalFileTypes; xmpPreferences = preferences.getXMPPreferences(); downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(1))); @@ -402,7 +405,7 @@ public void download() { URLDownload urlDownload = new URLDownload(linkedFile.getLink()); BackgroundTask downloadTask = prepareDownloadTask(targetDirectory.get(), urlDownload); downloadTask.onSuccess(destination -> { - LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(destination, databaseContext.getFileDirectoriesAsPaths(filePreferences)); + LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(destination, databaseContext.getFileDirectoriesAsPaths(filePreferences), externalFileTypes); linkedFile.setLink(newLinkedFile.getLink()); linkedFile.setFileType(newLinkedFile.getFileType()); }); @@ -420,7 +423,7 @@ public BackgroundTask prepareDownloadTask(Path targetDirectory, URLDownloa String suggestedTypeName = suggestedType.map(ExternalFileType::getName).orElse(""); linkedFile.setFileType(suggestedTypeName); - String suggestedName = linkedFileHandler.getSuggestedFileName(); + String suggestedName = linkedFileHandler.getSuggestedFileName(suggestedTypeName); return targetDirectory.resolve(suggestedName); }) .then(destination -> new FileDownloadTask(urlDownload.getSource(), destination)) @@ -443,7 +446,7 @@ private Optional inferFileTypeFromMimeType(URLDownload urlDown if (mimeType != null) { LOGGER.debug("MIME Type suggested: " + mimeType); - return ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(mimeType); + return externalFileTypes.getExternalFileTypeByMimeType(mimeType); } else { return Optional.empty(); } @@ -451,7 +454,7 @@ private Optional inferFileTypeFromMimeType(URLDownload urlDown private Optional inferFileTypeFromURL(String url) { return URLUtil.getSuffix(url) - .flatMap(extension -> ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension)); + .flatMap(extension -> externalFileTypes.getExternalFileTypeByExt(extension)); } public LinkedFile getFile() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 815d4be3a04..6b55626202f 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -48,6 +48,7 @@ public class LinkedFilesEditorViewModel extends AbstractEditorViewModel { private final BibDatabaseContext databaseContext; private final TaskExecutor taskExecutor; private final JabRefPreferences preferences; + private final ExternalFileTypes externalFileTypes = ExternalFileTypes.getInstance(); public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, @@ -55,6 +56,7 @@ public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvid TaskExecutor taskExecutor, FieldCheckers fieldCheckers, JabRefPreferences preferences) { + super(fieldName, suggestionProvider, fieldCheckers); this.dialogService = dialogService; @@ -62,7 +64,6 @@ public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvid this.taskExecutor = taskExecutor; this.preferences = preferences; - BindingsHelper.bindContentBidirectional( files, text, @@ -86,9 +87,9 @@ private static String getStringRepresentation(List files) { * * TODO: Move this method to {@link LinkedFile} as soon as {@link CustomExternalFileType} lives in model. */ - public static LinkedFile fromFile(Path file, List fileDirectories) { + public static LinkedFile fromFile(Path file, List fileDirectories, ExternalFileTypes externalFileTypesFile) { String fileExtension = FileHelper.getFileExtension(file).orElse(""); - ExternalFileType suggestedFileType = ExternalFileTypes.getInstance() + ExternalFileType suggestedFileType = externalFileTypesFile .getExternalFileTypeByExt(fileExtension) .orElse(new UnknownExternalFileType(fileExtension)); Path relativePath = FileUtil.relativize(file, fileDirectories); @@ -98,8 +99,8 @@ public static LinkedFile fromFile(Path file, List fileDirectories) { public LinkedFileViewModel fromFile(Path file) { List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFilePreferences()); - LinkedFile linkedFile = fromFile(file, fileDirectories); - return new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + LinkedFile linkedFile = fromFile(file, fileDirectories, externalFileTypes); + return new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileTypes); } @@ -113,7 +114,7 @@ public BooleanProperty fulltextLookupInProgressProperty() { private List parseToFileViewModel(String stringValue) { return FileFieldParser.parse(stringValue).stream() - .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences)) + .map(linkedFile -> new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileTypes)) .collect(Collectors.toList()); } @@ -135,8 +136,8 @@ public void addNewFile() { List fileDirectories = databaseContext.getFileDirectoriesAsPaths(preferences.getFilePreferences()); dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(newFile -> { - LinkedFile newLinkedFile = fromFile(newFile, fileDirectories); - files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, taskExecutor, dialogService, preferences)); + LinkedFile newLinkedFile = fromFile(newFile, fileDirectories, externalFileTypes); + files.add(new LinkedFileViewModel(newLinkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileTypes)); }); } @@ -162,7 +163,7 @@ private List findAssociatedNotLinkedFiles(BibEntry entry) { try { List linkedFiles = util.findAssociatedNotLinkedFiles(entry); for (LinkedFile linkedFile : linkedFiles) { - LinkedFileViewModel newLinkedFile = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + LinkedFileViewModel newLinkedFile = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileTypes); newLinkedFile.markAsAutomaticallyFound(); result.add(newLinkedFile); } @@ -205,7 +206,7 @@ public void addFromURL() { } private void addFromURL(URL url) { - LinkedFileViewModel onlineFile = new LinkedFileViewModel(new LinkedFile(url, ""), entry, databaseContext, taskExecutor, dialogService, preferences); + LinkedFileViewModel onlineFile = new LinkedFileViewModel(new LinkedFile(url, ""), entry, databaseContext, taskExecutor, dialogService, preferences, externalFileTypes); files.add(onlineFile); onlineFile.download(); } diff --git a/src/main/java/org/jabref/gui/filelist/AttachFileAction.java b/src/main/java/org/jabref/gui/filelist/AttachFileAction.java index 8ff43c37060..46d8f565437 100644 --- a/src/main/java/org/jabref/gui/filelist/AttachFileAction.java +++ b/src/main/java/org/jabref/gui/filelist/AttachFileAction.java @@ -6,6 +6,7 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.fieldeditors.LinkedFilesEditorViewModel; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.FileDialogConfiguration; @@ -38,7 +39,7 @@ public void execute() { dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(newFile -> { - LinkedFile linkedFile = LinkedFilesEditorViewModel.fromFile(newFile, panel.getBibDatabaseContext().getFileDirectoriesAsPaths(Globals.prefs.getFilePreferences())); + LinkedFile linkedFile = LinkedFilesEditorViewModel.fromFile(newFile, panel.getBibDatabaseContext().getFileDirectoriesAsPaths(Globals.prefs.getFilePreferences()), ExternalFileTypes.getInstance()); LinkedFileEditDialogView dialog = new LinkedFileEditDialogView(linkedFile); diff --git a/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java b/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java index 96005fc6b57..bfa7eb0ee97 100644 --- a/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java +++ b/src/main/java/org/jabref/gui/filelist/LinkedFilesEditDialogViewModel.java @@ -76,9 +76,9 @@ public void openBrowseDialog() { String fileName = Paths.get(fileText).getFileName().toString(); FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .withInitialDirectory(workingDir) - .withInitialFileName(fileName) - .build(); + .withInitialDirectory(workingDir) + .withInitialFileName(fileName) + .build(); dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(path -> { // Store the directory for next time: @@ -92,8 +92,11 @@ public void openBrowseDialog() { public void setValues(LinkedFile linkedFile) { description.set(linkedFile.getDescription()); - Path linkPath = Paths.get(linkedFile.getLink()); - link.set(relativize(linkPath)); + if (linkedFile.isOnlineLink()) { + link.setValue(linkedFile.getLink()); //Might be an URL + } else { + link.setValue(relativize(Paths.get(linkedFile.getLink()))); + } selectedExternalFileType.setValue(null); diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index 6133fc9c5e3..28ae799f41b 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -65,6 +65,7 @@ class MainTableColumnFactory { private final CellFactory cellFactory; private final UndoManager undoManager; private final DialogService dialogService; + public MainTableColumnFactory(BibDatabaseContext database, ColumnPreferences preferences, ExternalFileTypes externalFileTypes, UndoManager undoManager, DialogService dialogService) { this.database = Objects.requireNonNull(database); @@ -264,7 +265,7 @@ private TableColumn> createFileColumn() .withOnMouseClickedEvent((entry, linkedFiles) -> event -> { if ((event.getButton() == MouseButton.PRIMARY) && (linkedFiles.size() == 1)) { // Only one linked file -> open directly - LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, Globals.TASK_EXECUTOR, dialogService, Globals.prefs); + LinkedFileViewModel linkedFileViewModel = new LinkedFileViewModel(linkedFiles.get(0), entry.getEntry(), database, Globals.TASK_EXECUTOR, dialogService, Globals.prefs, externalFileTypes); linkedFileViewModel.open(); } }) @@ -287,7 +288,7 @@ private ContextMenu createFileMenu(BibEntryTableViewModel entry, List linkedFileViewModel.open()); diff --git a/src/main/java/org/jabref/logic/externalfiles/LinkedFileHandler.java b/src/main/java/org/jabref/logic/externalfiles/LinkedFileHandler.java index 04c26ab179e..4aaed7c5498 100644 --- a/src/main/java/org/jabref/logic/externalfiles/LinkedFileHandler.java +++ b/src/main/java/org/jabref/logic/externalfiles/LinkedFileHandler.java @@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory; public class LinkedFileHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(LinkedFileHandler.class); private final BibDatabaseContext databaseContext; @@ -84,7 +85,7 @@ public boolean renameToName(String targetFileName) throws IOException { String expandedOldFilePath = oldFile.get().toString(); boolean pathsDifferOnlyByCase = newPath.toString().equalsIgnoreCase(expandedOldFilePath) - && !newPath.toString().equals(expandedOldFilePath); + && !newPath.toString().equals(expandedOldFilePath); if (Files.exists(newPath) && !pathsDifferOnlyByCase) { // We do not overwrite files @@ -113,9 +114,14 @@ private String relativize(Path path) { public String getSuggestedFileName() { String oldFileName = fileEntry.getLink(); + String extension = FileHelper.getFileExtension(oldFileName).orElse(fileEntry.getFileType()); + return getSuggestedFileName(extension); + } + + public String getSuggestedFileName(String extension) { String targetFileName = FileUtil.createFileNameFromPattern(databaseContext.getDatabase(), entry, filePreferences.getFileNamePattern()).trim() - + '.' - + FileHelper.getFileExtension(oldFileName).orElse(fileEntry.getFileType()); + + '.' + + extension; // Only create valid file names return FileUtil.getValidFileName(targetFileName); diff --git a/src/main/java/org/jabref/logic/importer/IdBasedParserFetcher.java b/src/main/java/org/jabref/logic/importer/IdBasedParserFetcher.java index 29c1ded0e05..9dd2ec28401 100644 --- a/src/main/java/org/jabref/logic/importer/IdBasedParserFetcher.java +++ b/src/main/java/org/jabref/logic/importer/IdBasedParserFetcher.java @@ -11,8 +11,8 @@ import org.jabref.logic.net.URLDownload; import org.jabref.model.cleanup.Formatter; import org.jabref.model.entry.BibEntry; +import org.jabref.model.strings.StringUtil; -import org.jsoup.helper.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/jabref/logic/importer/SearchBasedParserFetcher.java b/src/main/java/org/jabref/logic/importer/SearchBasedParserFetcher.java index 4d1cf696ae6..dd7b732c9ff 100644 --- a/src/main/java/org/jabref/logic/importer/SearchBasedParserFetcher.java +++ b/src/main/java/org/jabref/logic/importer/SearchBasedParserFetcher.java @@ -11,8 +11,7 @@ import org.jabref.logic.net.URLDownload; import org.jabref.model.cleanup.Formatter; import org.jabref.model.entry.BibEntry; - -import org.jsoup.helper.StringUtil; +import org.jabref.model.strings.StringUtil; /** * Provides a convenient interface for search-based fetcher, which follow the usual three-step procedure: diff --git a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java index 6b99f420526..c940d07b193 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java @@ -30,10 +30,10 @@ import org.jabref.model.cleanup.FieldFormatterCleanup; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import org.jabref.model.strings.StringUtil; import org.jabref.model.util.DummyFileUpdateMonitor; import org.apache.http.client.utils.URIBuilder; -import org.jsoup.helper.StringUtil; /** * Fetches data from the SAO/NASA Astrophysics Data System (http://www.adsabs.harvard.edu/) diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IsbnFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/IsbnFetcher.java index c1d13f862e9..ac74cec7aca 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IsbnFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IsbnFetcher.java @@ -11,9 +11,9 @@ import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import org.jabref.model.strings.StringUtil; import org.jabref.model.util.OptionalUtil; -import org.jsoup.helper.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaChimboriFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaChimboriFetcher.java index 82c50b95ff4..4ddd9fa17a5 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaChimboriFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IsbnViaChimboriFetcher.java @@ -10,11 +10,11 @@ import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.ParseException; import org.jabref.model.entry.BibEntry; +import org.jabref.model.strings.StringUtil; import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; import com.mashape.unirest.http.exceptions.UnirestException; -import org.jsoup.helper.StringUtil; /** * Fetcher for ISBN using https://bibtex.chimbori.com/, which in turn uses Amazon's API. diff --git a/src/main/java/org/jabref/logic/shared/DBMSConnection.java b/src/main/java/org/jabref/logic/shared/DBMSConnection.java index 89952950add..9c2a3d09fdf 100644 --- a/src/main/java/org/jabref/logic/shared/DBMSConnection.java +++ b/src/main/java/org/jabref/logic/shared/DBMSConnection.java @@ -39,7 +39,6 @@ public DBMSConnection(DBMSConnectionProperties connectionProperties) throws SQLE // Some systems like PostgreSQL retrieves 0 to every exception. // Therefore a stable error determination is not possible. LOGGER.error("Could not connect to database: " + e.getMessage() + " - Error code: " + e.getErrorCode()); - throw e; } } diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index 7a7893c6d79..fab6942fc8b 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -1,25 +1,36 @@ package org.jabref.gui.fieldeditors; +import java.net.MalformedURLException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.Optional; +import java.util.TreeSet; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.ButtonType; import org.jabref.gui.DialogService; +import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.externalfiletype.StandardExternalFileType; +import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.CurrentThreadTaskExecutor; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.net.URLDownload; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FilePreferences; import org.jabref.preferences.JabRefPreferences; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -39,14 +50,20 @@ class LinkedFileViewModelTest { private BibDatabaseContext databaseContext; private TaskExecutor taskExecutor; private DialogService dialogService; + private ExternalFileTypes externalFileType = mock(ExternalFileTypes.class); + private FilePreferences filePreferences = mock(FilePreferences.class); @BeforeEach void setUp(@TempDir Path tempFolder) throws Exception { entry = new BibEntry(); + entry.setCiteKey("asdf"); databaseContext = new BibDatabaseContext(); taskExecutor = mock(TaskExecutor.class); dialogService = mock(DialogService.class); + when(externalFileType.getExternalFileTypeSelection()).thenReturn(new TreeSet<>(ExternalFileTypes.getDefaultExternalFileTypes())); + when(externalFileType.getExternalFileTypeByMimeType("application/pdf")).thenReturn(Optional.of(StandardExternalFileType.PDF)); + when(externalFileType.getExternalFileTypeByExt("pdf")).thenReturn(Optional.of(StandardExternalFileType.PDF)); tempFile = tempFolder.resolve("temporaryFile"); Files.createFile(tempFile); } @@ -57,7 +74,7 @@ void deleteWhenFilePathNotPresentReturnsTrue() { linkedFile = spy(new LinkedFile("", "nonexistent file", "")); doReturn(Optional.empty()).when(linkedFile).findIn(any(BibDatabaseContext.class), any(FilePreferences.class)); - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileType); boolean removed = viewModel.delete(); assertTrue(removed); @@ -68,14 +85,14 @@ void deleteWhenFilePathNotPresentReturnsTrue() { void deleteWhenRemoveChosenReturnsTrueButDoesNotDeletesFile() { linkedFile = new LinkedFile("", tempFile.toString(), ""); when(dialogService.showCustomButtonDialogAndWait( - any(AlertType.class), - anyString(), - anyString(), - any(ButtonType.class), - any(ButtonType.class), - any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(3))); // first vararg - remove button - - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + any(AlertType.class), + anyString(), + anyString(), + any(ButtonType.class), + any(ButtonType.class), + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(3))); // first vararg - remove button + + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileType); boolean removed = viewModel.delete(); assertTrue(removed); @@ -86,14 +103,14 @@ void deleteWhenRemoveChosenReturnsTrueButDoesNotDeletesFile() { void deleteWhenDeleteChosenReturnsTrueAndDeletesFile() { linkedFile = new LinkedFile("", tempFile.toString(), ""); when(dialogService.showCustomButtonDialogAndWait( - any(AlertType.class), - anyString(), - anyString(), - any(ButtonType.class), - any(ButtonType.class), - any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button - - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + any(AlertType.class), + anyString(), + anyString(), + any(ButtonType.class), + any(ButtonType.class), + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button + + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileType); boolean removed = viewModel.delete(); assertTrue(removed); @@ -104,14 +121,14 @@ void deleteWhenDeleteChosenReturnsTrueAndDeletesFile() { void deleteMissingFileReturnsTrue() { linkedFile = new LinkedFile("", "!!nonexistent file!!", ""); when(dialogService.showCustomButtonDialogAndWait( - any(AlertType.class), - anyString(), - anyString(), - any(ButtonType.class), - any(ButtonType.class), - any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button - - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + any(AlertType.class), + anyString(), + anyString(), + any(ButtonType.class), + any(ButtonType.class), + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(4))); // second vararg - delete button + + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileType); boolean removed = viewModel.delete(); assertTrue(removed); @@ -121,17 +138,37 @@ void deleteMissingFileReturnsTrue() { void deleteWhenDialogCancelledReturnsFalseAndDoesNotRemoveFile() { linkedFile = new LinkedFile("desc", tempFile.toString(), "pdf"); when(dialogService.showCustomButtonDialogAndWait( - any(AlertType.class), - anyString(), - anyString(), - any(ButtonType.class), - any(ButtonType.class), - any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(5))); // third vararg - cancel button - - LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences); + any(AlertType.class), + anyString(), + anyString(), + any(ButtonType.class), + any(ButtonType.class), + any(ButtonType.class))).thenAnswer(invocation -> Optional.of(invocation.getArgument(5))); // third vararg - cancel button + + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, taskExecutor, dialogService, preferences, externalFileType); boolean removed = viewModel.delete(); assertFalse(removed); assertTrue(Files.exists(tempFile)); } + + @Test + void downloadDoesNotOverwriteFileTypeExtension() throws MalformedURLException { + linkedFile = new LinkedFile(new URL("http://arxiv.org/pdf/1207.0408v1"), ""); + + databaseContext = mock(BibDatabaseContext.class); + when(filePreferences.getFileNamePattern()).thenReturn("[bibtexkey]"); //use this variant, as we cannot mock the linkedFileHandler cause it's initialized inside the viewModel + when(preferences.getFilePreferences()).thenReturn(filePreferences); + + LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, new CurrentThreadTaskExecutor(), dialogService, preferences, externalFileType); + + BackgroundTask task = viewModel.prepareDownloadTask(tempFile.getParent(), new URLDownload("http://arxiv.org/pdf/1207.0408v1")); + task.onSuccess(destination -> { + LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(destination, Collections.singletonList(tempFile.getParent()), externalFileType); + assertEquals("asdf.PDF", newLinkedFile.getLink()); + assertEquals("PDF", newLinkedFile.getFileType()); + }); + task.onFailure(Assertions::fail); + new CurrentThreadTaskExecutor().execute(task); + } }