From e0460ddf9485888aad9c882769eace2d8a74b192 Mon Sep 17 00:00:00 2001 From: Rifat Hossain <31892050+Rifat951@users.noreply.github.com> Date: Wed, 18 May 2022 02:28:16 +0930 Subject: [PATCH 01/10] updated 8802 (#8817) --- CHANGELOG.md | 1 + .../jabref/gui/maintable/columns/LinkedIdentifierColumn.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1d48b3f465..6ddb17da2a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed the unnecessary horizontal scroll bar in group panel [#8467](https://github.com/JabRef/jabref/issues/8467) - We fixed an issue where the notification bar message, icon and actions appeared to be invisible. [#8761](https://github.com/JabRef/jabref/issues/8761) - We fixed an issue where deprecated fields tab is shown when the fields don't contain any values. [#8396](https://github.com/JabRef/jabref/issues/8396) +- We fixed an issue which allow us to select and open identifiers from a popup list in the maintable [#8758](https://github.com/JabRef/jabref/issues/8758), [8802](https://github.com/JabRef/jabref/issues/8802) ### Removed diff --git a/src/main/java/org/jabref/gui/maintable/columns/LinkedIdentifierColumn.java b/src/main/java/org/jabref/gui/maintable/columns/LinkedIdentifierColumn.java index d150bcde358..55f780fe5d3 100644 --- a/src/main/java/org/jabref/gui/maintable/columns/LinkedIdentifierColumn.java +++ b/src/main/java/org/jabref/gui/maintable/columns/LinkedIdentifierColumn.java @@ -60,7 +60,7 @@ public LinkedIdentifierColumn(MainTableColumnModel model, .withTooltip(this::createIdentifierTooltip) .withMenu(this::createIdentifierMenu) .withOnMouseClickedEvent((entry, linkedFiles) -> event -> { - if ((event.getButton() == MouseButton.PRIMARY)) { + if ((event.getButton() == MouseButton.SECONDARY)) { new OpenUrlAction(dialogService, stateManager, preferences).execute(); } }) From 82aad89a12a43f120072d27cb3a9eeb5107aeab0 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Tue, 17 May 2022 19:11:38 +0200 Subject: [PATCH 02/10] Restrict use of standard streams (#8816) * Added architecture test * Refined test * Applied test results * Add reason * Update src/test/java/org/jabref/logic/exporter/ModsExportFormatFilesTest.java * Update src/test/java/org/jabref/logic/util/io/FileUtilTest.java * Checkstyle Co-authored-by: Christoph --- .../AllowedToUseStandardStreams.java | 10 ++++++++ .../java/org/jabref/gui/desktop/os/Linux.java | 8 +++---- .../org/jabref/logic/util/io/XMLUtil.java | 3 +++ .../architecture/MainArchitectureTests.java | 14 ++++++++++- ...es.java => ModsExportFormatFilesTest.java} | 24 ++++++++++--------- .../jabref/logic/git/SlrGitHandlerTest.java | 6 ++++- .../org/jabref/logic/net/URLDownloadTest.java | 5 +++- .../jabref/logic/util/io/FileUtilTest.java | 6 ++++- 8 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/jabref/architecture/AllowedToUseStandardStreams.java rename src/test/java/org/jabref/logic/exporter/{ModsExportFormatTestFiles.java => ModsExportFormatFilesTest.java} (85%) diff --git a/src/main/java/org/jabref/architecture/AllowedToUseStandardStreams.java b/src/main/java/org/jabref/architecture/AllowedToUseStandardStreams.java new file mode 100644 index 00000000000..1fe80af54d7 --- /dev/null +++ b/src/main/java/org/jabref/architecture/AllowedToUseStandardStreams.java @@ -0,0 +1,10 @@ +package org.jabref.architecture; + +/** + * Annotation to indicate that this class can use System.Out.* instead of using the logging framework + */ +public @interface AllowedToUseStandardStreams { + + // The rationale + String value(); +} 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 e4a73faa177..5982107fdd5 100644 --- a/src/main/java/org/jabref/gui/desktop/os/Linux.java +++ b/src/main/java/org/jabref/gui/desktop/os/Linux.java @@ -28,17 +28,17 @@ private void nativeOpenFile(String filePath) { try { File file = new File(filePath); Desktop.getDesktop().open(file); - System.out.println("Open file in default application with Desktop integration"); + LOGGER.debug("Open file in default application with Desktop integration"); } catch (IllegalArgumentException e) { - System.out.println("Fail back to xdg-open"); + LOGGER.debug("Fail back to xdg-open"); try { String[] cmd = {"xdg-open", filePath}; Runtime.getRuntime().exec(cmd); } catch (Exception e2) { - System.out.println("Open operation not successful: " + e2); + LOGGER.warn("Open operation not successful: " + e2); } } catch (IOException e) { - System.out.println("Native open operation not successful: " + e); + LOGGER.warn("Native open operation not successful: " + e); } }); } diff --git a/src/main/java/org/jabref/logic/util/io/XMLUtil.java b/src/main/java/org/jabref/logic/util/io/XMLUtil.java index 3bff65dbb34..b6126914de3 100644 --- a/src/main/java/org/jabref/logic/util/io/XMLUtil.java +++ b/src/main/java/org/jabref/logic/util/io/XMLUtil.java @@ -14,6 +14,8 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.jabref.architecture.AllowedToUseStandardStreams; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -25,6 +27,7 @@ /** * Currently used for debugging only */ +@AllowedToUseStandardStreams("Used for debugging only") public class XMLUtil { private static final Logger LOGGER = LoggerFactory.getLogger(XMLUtil.class); diff --git a/src/test/java/org/jabref/architecture/MainArchitectureTests.java b/src/test/java/org/jabref/architecture/MainArchitectureTests.java index 40e3d945f2b..6aafd6acc1a 100644 --- a/src/test/java/org/jabref/architecture/MainArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/MainArchitectureTests.java @@ -6,6 +6,7 @@ import com.tngtech.archunit.junit.AnalyzeClasses; import com.tngtech.archunit.junit.ArchIgnore; import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.library.GeneralCodingRules; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; import static com.tngtech.archunit.library.Architectures.layeredArchitecture; @@ -20,6 +21,7 @@ class MainArchitectureTests { private static final String PACKAGE_ORG_JABREF_GUI = "org.jabref.gui.."; private static final String PACKAGE_ORG_JABREF_LOGIC = "org.jabref.logic.."; private static final String PACKAGE_ORG_JABREF_MODEL = "org.jabref.model.."; + private static final String PACKAGE_ORG_JABREF_CLI = "org.jabref.cli.."; @ArchTest public static void doNotUseApacheCommonsLang3(JavaClasses classes) { @@ -92,7 +94,7 @@ public static void respectLayeredArchitecture(JavaClasses classes) { .layer("Gui").definedBy(PACKAGE_ORG_JABREF_GUI) .layer("Logic").definedBy(PACKAGE_ORG_JABREF_LOGIC) .layer("Model").definedBy(PACKAGE_ORG_JABREF_MODEL) - .layer("Cli").definedBy("org.jabref.cli..") + .layer("Cli").definedBy(PACKAGE_ORG_JABREF_CLI) .layer("Migrations").definedBy("org.jabref.migrations..") // TODO: Move to logic .layer("Preferences").definedBy("org.jabref.preferences..") .layer("Styletester").definedBy("org.jabref.styletester..") @@ -135,4 +137,14 @@ public static void restrictUsagesInLogic(JavaClasses classes) { .orShould().dependOnClassesThat().haveFullyQualifiedName(CLASS_ORG_JABREF_GLOBALS) .check(classes); } + + @ArchTest + public static void restrictStandardStreams(JavaClasses classes) { + noClasses().that().resideOutsideOfPackages(PACKAGE_ORG_JABREF_CLI) + .and().resideOutsideOfPackages("org.jabref.gui.openoffice..") // Uses LibreOffice SDK + .and().areNotAnnotatedWith(AllowedToUseStandardStreams.class) + .should(GeneralCodingRules.ACCESS_STANDARD_STREAMS) + .because("logging framework should be used instead or the class be marked explicitly as @AllowedToUseStandardStreams") + .check(classes); + } } diff --git a/src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java b/src/test/java/org/jabref/logic/exporter/ModsExportFormatFilesTest.java similarity index 85% rename from src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java rename to src/test/java/org/jabref/logic/exporter/ModsExportFormatFilesTest.java index 22f33319112..567459318c6 100644 --- a/src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java +++ b/src/test/java/org/jabref/logic/exporter/ModsExportFormatFilesTest.java @@ -5,7 +5,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.jabref.logic.bibtex.BibEntryAssert; @@ -22,14 +21,18 @@ import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Answers; import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -public class ModsExportFormatTestFiles { - +public class ModsExportFormatFilesTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ModsExportFormatFilesTest.class); private static Path resourceDir; + public Charset charset; + private BibDatabaseContext databaseContext; private Path exportedFile; private ModsExporter exporter; @@ -39,12 +42,11 @@ public class ModsExportFormatTestFiles { public static Stream fileNames() throws Exception { resourceDir = Path.of(MSBibExportFormatTestFiles.class.getResource("ModsExportFormatTestAllFields.bib").toURI()).getParent(); - System.out.println(resourceDir); + LOGGER.debug("Mods export resouce dir {}", resourceDir); try (Stream stream = Files.list(resourceDir)) { - // stream.forEach(n -> System.out.println(n)); return stream.map(n -> n.getFileName().toString()).filter(n -> n.endsWith(".bib")) - .filter(n -> n.startsWith("Mods")).collect(Collectors.toList()).stream(); + .filter(n -> n.startsWith("Mods")).toList().stream(); } } @@ -65,10 +67,10 @@ public void setUp(@TempDir Path testFolder) throws Exception { @ParameterizedTest @MethodSource("fileNames") public final void testPerformExport(String filename) throws Exception { - importFile = Path.of(ModsExportFormatTestFiles.class.getResource(filename).toURI()); + importFile = Path.of(ModsExportFormatFilesTest.class.getResource(filename).toURI()); String xmlFileName = filename.replace(".bib", ".xml"); List entries = bibtexImporter.importDatabase(importFile).getDatabase().getEntries(); - Path expectedFile = Path.of(ModsExportFormatTestFiles.class.getResource(xmlFileName).toURI()); + Path expectedFile = Path.of(ModsExportFormatFilesTest.class.getResource(xmlFileName).toURI()); exporter.export(databaseContext, exportedFile, entries); @@ -80,7 +82,7 @@ public final void testPerformExport(String filename) throws Exception { @ParameterizedTest @MethodSource("fileNames") public final void testExportAsModsAndThenImportAsMods(String filename) throws Exception { - importFile = Path.of(ModsExportFormatTestFiles.class.getResource(filename).toURI()); + importFile = Path.of(ModsExportFormatFilesTest.class.getResource(filename).toURI()); List entries = bibtexImporter.importDatabase(importFile).getDatabase().getEntries(); exporter.export(databaseContext, exportedFile, entries); @@ -90,9 +92,9 @@ public final void testExportAsModsAndThenImportAsMods(String filename) throws Ex @ParameterizedTest @MethodSource("fileNames") public final void testImportAsModsAndExportAsMods(String filename) throws Exception { - importFile = Path.of(ModsExportFormatTestFiles.class.getResource(filename).toURI()); + importFile = Path.of(ModsExportFormatFilesTest.class.getResource(filename).toURI()); String xmlFileName = filename.replace(".bib", ".xml"); - Path xmlFile = Path.of(ModsExportFormatTestFiles.class.getResource(xmlFileName).toURI()); + Path xmlFile = Path.of(ModsExportFormatFilesTest.class.getResource(xmlFileName).toURI()); List entries = modsImporter.importDatabase(xmlFile).getDatabase().getEntries(); diff --git a/src/test/java/org/jabref/logic/git/SlrGitHandlerTest.java b/src/test/java/org/jabref/logic/git/SlrGitHandlerTest.java index d18c3374e7c..af4b13a1f1b 100644 --- a/src/test/java/org/jabref/logic/git/SlrGitHandlerTest.java +++ b/src/test/java/org/jabref/logic/git/SlrGitHandlerTest.java @@ -10,10 +10,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.junit.jupiter.api.Assertions.assertEquals; class SlrGitHandlerTest { + private static final Logger LOGGER = LoggerFactory.getLogger(SlrGitHandlerTest.class); + @TempDir Path repositoryPath; private SlrGitHandler gitHandler; @@ -44,7 +48,7 @@ void calculateDiffOnBranch() throws IOException, GitAPIException { Files.writeString(Path.of(repositoryPath.toString(), "TestFolder", "Test1.txt"), "This is a new line of text 2\n" + Files.readString(Path.of(repositoryPath.toString(), "TestFolder", "Test1.txt"))); gitHandler.createCommitOnCurrentBranch("Commit 2 on branch1", false); - System.out.println(gitHandler.calculatePatchOfNewSearchResults("branch1")); + LOGGER.debug(gitHandler.calculatePatchOfNewSearchResults("branch1")); assertEquals(expectedPatch, gitHandler.calculatePatchOfNewSearchResults("branch1")); } diff --git a/src/test/java/org/jabref/logic/net/URLDownloadTest.java b/src/test/java/org/jabref/logic/net/URLDownloadTest.java index 8891cb91579..84c63c6b74d 100644 --- a/src/test/java/org/jabref/logic/net/URLDownloadTest.java +++ b/src/test/java/org/jabref/logic/net/URLDownloadTest.java @@ -11,12 +11,15 @@ import kong.unirest.UnirestException; import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class URLDownloadTest { + private static final Logger LOGGER = LoggerFactory.getLogger(URLDownloadTest.class); @Test public void testStringDownloadWithSetEncoding() throws IOException { @@ -42,7 +45,7 @@ public void testFileDownload() throws IOException { } finally { // cleanup if (!destination.delete()) { - System.err.println("Cannot delete downloaded file"); + LOGGER.error("Cannot delete downloaded file"); } } } 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 f1b9d1f76d2..3c82fa8453e 100644 --- a/src/test/java/org/jabref/logic/util/io/FileUtilTest.java +++ b/src/test/java/org/jabref/logic/util/io/FileUtilTest.java @@ -20,6 +20,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -29,6 +31,8 @@ import static org.mockito.Mockito.mock; class FileUtilTest { + private static final Logger LOGGER = LoggerFactory.getLogger(FileUtilTest.class); + private final Path nonExistingTestPath = Path.of("nonExistingTestPath"); private Path existingTestFile; private Path otherExistingTestFile; @@ -319,7 +323,7 @@ void testRenameFileSuccessful(@TempDir Path otherTemporaryFolder) { // in the @BeforeEach method. Path temp = Path.of(otherTemporaryFolder.resolve("123").toString()); - System.out.println(temp); + LOGGER.debug("Temp dir {}", temp); FileUtil.renameFile(existingTestFile, temp); assertFalse(Files.exists(existingTestFile)); } From 42672e3af124c74a4c9e46f7b5262a95498218c2 Mon Sep 17 00:00:00 2001 From: Christina0114 <39109002+Christina0114@users.noreply.github.com> Date: Wed, 18 May 2022 10:08:08 -0700 Subject: [PATCH 03/10] add: add test cases for FileUtil (#8810) * add: add test cases for FileUtil * del: other * fix: list of * fix: list of Co-authored-by: Christina Chen --- .../org/jabref/logic/util/io/FileUtilTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 3c82fa8453e..ce6f126c045 100644 --- a/src/test/java/org/jabref/logic/util/io/FileUtilTest.java +++ b/src/test/java/org/jabref/logic/util/io/FileUtilTest.java @@ -387,4 +387,18 @@ void testIsNotBibFile() throws IOException { Path bibFile = Files.createFile(rootDir.resolve("test.pdf")); assertFalse(FileUtil.isBibFile(bibFile)); } + + @Test + void testFindinPath() { + Optional resultPath1 = FileUtil.find("existingTestFile.txt", rootDir); + assertEquals(resultPath1.get().toString(), existingTestFile.toString()); + } + + @Test + void testFindinListofPath() { + List paths = List.of(existingTestFile, otherExistingTestFile, rootDir); + List resultPaths = List.of(existingTestFile, existingTestFile); + List result = FileUtil.find("existingTestFile.txt", paths); + assertEquals(resultPaths, result); + } } From 57f1a0ddbd5aa7f7950ea39cfd9b727072a5a0d2 Mon Sep 17 00:00:00 2001 From: Christoph Date: Wed, 18 May 2022 20:01:44 +0200 Subject: [PATCH 04/10] Update bouncycalse to new base version (#8827) The jdk18on jars are compiled to work with anything from Java 1.8 up. https://www.bouncycastle.org/latest_releases.html --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5adec12d8de..b3ea4900fca 100644 --- a/build.gradle +++ b/build.gradle @@ -126,7 +126,7 @@ dependencies { implementation 'com.ibm.icu:icu4j-charset:71.1' // required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635 - implementation 'org.bouncycastle:bcprov-jdk15on:1.70' + implementation 'org.bouncycastle:bcprov-jdk18on:1.71' implementation 'commons-cli:commons-cli:1.5.0' From d6e1b16d552f6f5f318dcf2d67833483d5e658a8 Mon Sep 17 00:00:00 2001 From: Kevin Klein <38384885+0x002A@users.noreply.github.com> Date: Wed, 18 May 2022 23:52:21 +0200 Subject: [PATCH 05/10] Fix missing clear action on pressing esc within the "Filter groups" field (#8829) --- CHANGELOG.md | 1 + .../java/org/jabref/gui/keyboard/TextInputKeyBindings.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ddb17da2a8..780453db7c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where the notification bar message, icon and actions appeared to be invisible. [#8761](https://github.com/JabRef/jabref/issues/8761) - We fixed an issue where deprecated fields tab is shown when the fields don't contain any values. [#8396](https://github.com/JabRef/jabref/issues/8396) - We fixed an issue which allow us to select and open identifiers from a popup list in the maintable [#8758](https://github.com/JabRef/jabref/issues/8758), [8802](https://github.com/JabRef/jabref/issues/8802) +- We fixed an issue where the escape button had no functionality within the "Filter groups" textfield. [koppor#562](https://github.com/koppor/jabref/issues/562) ### Removed diff --git a/src/main/java/org/jabref/gui/keyboard/TextInputKeyBindings.java b/src/main/java/org/jabref/gui/keyboard/TextInputKeyBindings.java index d195f0bdef8..d63ac9459c2 100644 --- a/src/main/java/org/jabref/gui/keyboard/TextInputKeyBindings.java +++ b/src/main/java/org/jabref/gui/keyboard/TextInputKeyBindings.java @@ -90,6 +90,10 @@ public static void call(Scene scene, KeyEvent event) { focusedTextField.positionCaret(res.caretPosition); event.consume(); } + case CLOSE -> { + focusedTextField.clear(); + event.consume(); + } } }); } From 4baf2a1b86ed5aaac4455d52551602c6bea430ed Mon Sep 17 00:00:00 2001 From: Galileo Sartor Date: Thu, 19 May 2022 14:03:39 +0200 Subject: [PATCH 06/10] Add Nemo file manager (#8831) --- src/main/java/org/jabref/gui/desktop/os/Linux.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 5982107fdd5..51684b5a77a 100644 --- a/src/main/java/org/jabref/gui/desktop/os/Linux.java +++ b/src/main/java/org/jabref/gui/desktop/os/Linux.java @@ -94,9 +94,13 @@ public void openFolderAndSelectFile(Path filePath) throws IOException { if (desktopSession != null) { desktopSession = desktopSession.toLowerCase(Locale.ROOT); if (desktopSession.contains("gnome")) { - cmd = "nautilus" + filePath.toString().replace(" ", "\\ "); - } else if (desktopSession.contains("kde")) { + cmd = "nautilus --select " + filePath.toString().replace(" ", "\\ "); + } else if (desktopSession.contains("kde") || desktopSession.contains("plasma")) { cmd = "dolphin --select " + filePath.toString().replace(" ", "\\ "); + } else if (desktopSession.contains("mate")) { + cmd = "caja --select " + filePath.toString().replace(" ", "\\ "); + } else if (desktopSession.contains("cinnamon")) { + cmd = "nemo --select " + filePath.toString().replace(" ", "\\ "); } } Runtime.getRuntime().exec(cmd); From 1a1cfd3d702e09ab4c5bf393270fefd1650c4bc9 Mon Sep 17 00:00:00 2001 From: Christoph Date: Thu, 19 May 2022 18:36:04 +0200 Subject: [PATCH 07/10] Fix eclipse config (#8835) --- eclipse.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/eclipse.gradle b/eclipse.gradle index b82fd8bca2b..dab4df54bb6 100644 --- a/eclipse.gradle +++ b/eclipse.gradle @@ -25,11 +25,15 @@ eclipse { } def javafxcontrols = entries.find { isJavafxControls(it) }; - javafxcontrols.entryAttributes['add-exports'] = 'javafx.controls/com.sun.javafx.scene.control=org.jabref:javafx.controls/com.sun.javafx.scene.control.behavior=org.jabref:javafx.controls/javafx.scene.control=org.jabref'; + javafxcontrols.entryAttributes['add-exports'] = 'javafx.controls/com.sun.javafx.scene.control=org.jabref:javafx.controls/com.sun.javafx.scene.control.behavior=org.jabref:javafx.controls/javafx.scene.control=org.jabref:javafx.controls/com.sun.javafx.scene.control.behavior=com.jfoenix'; javafxcontrols.entryAttributes['add-opens'] = 'javafx.controls/com.sun.javafx.scene.control=org.jabref:javafx.controls/com.sun.javafx.scene.control.behavior=org.jabref:javafx.controls/javafx.scene.control=org.jabref:javafx.controls/javafx.scene.control.skin=org.controlsfx.controls'; def javafxgraphics = entries.find { isJavafxGraphics(it) }; javafxgraphics.entryAttributes['add-opens'] = 'javafx.graphics/javafx.scene=org.controlsfx.controls'; + javafxgraphics.entryAttributes['add-exports'] = 'javafx.graphics/com.sun.javafx.stage=com.jfoenix'; + + def javafxbase = entries.find { isJavafxBase(it) }; + javafxbase.entryAttributes['add-exports'] = 'javafx.base/com.sun.javafx.event=org.controlsfx.controls:'; def javafxfxml = entries.find { isJavafxFXML(it) }; javafxfxml.entryAttributes['add-opens'] = 'javafx.fxml/javafx.fxml=org.jabref'; @@ -61,6 +65,8 @@ boolean isJavafxControls(entry) { return entry.properties.path.contains('javafx- boolean isJavafxGraphics(entry) { return entry.properties.path.contains('javafx-graphics'); } +boolean isJavafxBase(entry) { return entry.properties.path.contains('javafx-base'); } + boolean isJavafxFXML(entry) { return entry.properties.path.contains('javafx-fxml'); } // add formatter and cleanup settings to Eclipse settings From 7a81b62fc081926c260583f3ffe9f1755417e114 Mon Sep 17 00:00:00 2001 From: Christoph Date: Thu, 19 May 2022 21:04:52 +0200 Subject: [PATCH 08/10] Append config instead of replacing (#8834) Fixes #8833 --- src/main/java/org/jabref/gui/JabRefMain.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/JabRefMain.java b/src/main/java/org/jabref/gui/JabRefMain.java index 8dfe66dfd22..531afa12290 100644 --- a/src/main/java/org/jabref/gui/JabRefMain.java +++ b/src/main/java/org/jabref/gui/JabRefMain.java @@ -80,7 +80,8 @@ private static void addLogToDisk() { "writerFile.level", "info", "writerFile.file", directory.resolve("log.txt").toString(), "writerFile.charset", "UTF-8"); - Configuration.replace(configuration); + + configuration.entrySet().forEach(config -> Configuration.set(config.getKey(), config.getValue())); initializeLogger(); } From b4e08ac47db517dfb5d5beaeafbcbbc4e216eb5f Mon Sep 17 00:00:00 2001 From: Ching-Yang Lin <33810960+tomlinn@users.noreply.github.com> Date: Sat, 21 May 2022 09:23:00 -0700 Subject: [PATCH 09/10] adjust and add testcases for FileAnnotationViewModel (#8830) * adjust and add testcases for FileAnnotationViewModel * fix checkstyle Co-authored-by: tomlin --- .../FileAnnotationViewModel.java | 22 +++++++++---------- .../FileAnnotationViewModelTest.java | 18 ++++++++++++++- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationViewModel.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationViewModel.java index 6f90512195a..62cd3d53491 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationViewModel.java +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationViewModel.java @@ -4,7 +4,6 @@ import javafx.beans.property.StringProperty; import org.jabref.logic.formatter.bibtexfields.RemoveHyphenatedNewlinesFormatter; -import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.model.pdf.FileAnnotation; import org.jabref.model.pdf.FileAnnotationType; @@ -33,22 +32,23 @@ private void setupContentProperties(FileAnnotation annotation) { String annotationContent = annotation.getContent(); String illegibleTextMessage = Localization.lang("The marked area does not contain any legible text!"); String markingContent = (annotationContent.isEmpty() ? illegibleTextMessage : annotationContent); - // remove newlines && hyphens before linebreaks - markingContent = markingContent.replaceAll("-" + NEWLINE, ""); - new RemoveHyphenatedNewlinesFormatter().format(markingContent); - // remove new lines not preceded by '.' or ':' - markingContent = markingContent.replaceAll("(? Date: Sat, 21 May 2022 18:28:38 +0200 Subject: [PATCH 10/10] Add Pubmed/Medline Query Transformer (#8818) * Add Pubmed/Medline Query Transformer Supports the default search fields and boolean operators Fixes https://discourse.jabref.org/t/native-pubmed-search/3354 * checkstyle * Update SuffixTransformerTest.java --- CHANGELOG.md | 1 + .../importer/fetcher/MedlineFetcher.java | 16 +--- .../transformers/MedlineQueryTransformer.java | 54 +++++++++++ .../importer/fetcher/MedlineFetcherTest.java | 14 +++ .../IEEEQueryTransformerTest.java | 2 +- .../transformers/InfixTransformerTest.java | 30 +++--- .../transformers/SuffixTransformerTest.java | 94 +++++++++++++++++++ 7 files changed, 186 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/jabref/logic/importer/fetcher/transformers/MedlineQueryTransformer.java create mode 100644 src/test/java/org/jabref/logic/importer/fetcher/transformers/SuffixTransformerTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 780453db7c9..8af025df4c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - Writing BibTeX data into a PDF (XMP) removes braces. [#8452](https://github.com/JabRef/jabref/issues/8452) - Writing BibTeX data into a PDF (XMP) does not write the `file` field. - Writing BibTeX data into a PDF (XMP) considers the configured keyword separator (and does not use "," as default any more) +- The Medline/Pubmed search now also supports the [default fields and operators for searching](https://docs.jabref.org/collect/import-using-online-bibliographic-database#search-syntax). [forum#3554](https://discourse.jabref.org/t/native-pubmed-search/3354) ### Fixed diff --git a/src/main/java/org/jabref/logic/importer/fetcher/MedlineFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/MedlineFetcher.java index 42731cc1ae5..b37eb30daed 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/MedlineFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/MedlineFetcher.java @@ -28,7 +28,7 @@ import org.jabref.logic.importer.Parser; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.importer.SearchBasedFetcher; -import org.jabref.logic.importer.fetcher.transformers.DefaultQueryTransformer; +import org.jabref.logic.importer.fetcher.transformers.MedlineQueryTransformer; import org.jabref.logic.importer.fileformat.MedlineImporter; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -54,16 +54,6 @@ public class MedlineFetcher implements IdBasedParserFetcher, SearchBasedFetcher private int numberOfResultsFound; - /** - * Replaces all commas in a given string with " AND " - * - * @param query input to remove commas - * @return input without commas - */ - private static String replaceCommaWithAND(String query) { - return query.replaceAll(", ", " AND ").replaceAll(",", " AND "); - } - /** * When using 'esearch.fcgi?db=<database>&term=<query>' we will get a list of IDs matching the query. * Input: Any text query (&term) @@ -164,7 +154,7 @@ private URL createSearchUrl(String query) throws URISyntaxException, MalformedUR uriBuilder.addParameter("db", "pubmed"); uriBuilder.addParameter("sort", "relevance"); uriBuilder.addParameter("retmax", String.valueOf(NUMBER_TO_FETCH)); - uriBuilder.addParameter("term", replaceCommaWithAND(query)); + uriBuilder.addParameter("term", query); // already lucene query return uriBuilder.build().toURL(); } @@ -200,7 +190,7 @@ private List fetchMedline(List ids) throws FetcherException { @Override public List performSearch(QueryNode luceneQuery) throws FetcherException { List entryList; - DefaultQueryTransformer transformer = new DefaultQueryTransformer(); + MedlineQueryTransformer transformer = new MedlineQueryTransformer(); Optional transformedQuery = transformer.transformLuceneQuery(luceneQuery); if (transformedQuery.isEmpty() || transformedQuery.get().isBlank()) { diff --git a/src/main/java/org/jabref/logic/importer/fetcher/transformers/MedlineQueryTransformer.java b/src/main/java/org/jabref/logic/importer/fetcher/transformers/MedlineQueryTransformer.java new file mode 100644 index 00000000000..155b08b89d2 --- /dev/null +++ b/src/main/java/org/jabref/logic/importer/fetcher/transformers/MedlineQueryTransformer.java @@ -0,0 +1,54 @@ +package org.jabref.logic.importer.fetcher.transformers; + +/** + * + * Medline/Pubmed specific transformer which uses suffixes for searches + * see Pubmed help for details + * + */ +public class MedlineQueryTransformer extends AbstractQueryTransformer { + + @Override + protected String getLogicalAndOperator() { + return " AND "; + } + + @Override + protected String getLogicalOrOperator() { + return " OR "; + } + + @Override + protected String getLogicalNotOperator() { + return "NOT "; + } + + @Override + protected String handleAuthor(String author) { + return author + "[au]"; + } + + @Override + protected String handleTitle(String title) { + return title + "[ti]"; + } + + @Override + protected String handleJournal(String journalTitle) { + return journalTitle + "[ta]"; + } + + @Override + protected String handleYear(String year) { + return year + "[dp]"; + } + + @Override + protected String handleYearRange(String yearRange) { + parseYearRange(yearRange); + if (endYear == Integer.MAX_VALUE) { + return yearRange; + } + return Integer.toString(startYear) + ":" + Integer.toString(endYear) + "[dp]"; + } +} diff --git a/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java index 1129c034683..c0e35312e49 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java @@ -172,6 +172,20 @@ public void testMultipleEntries() throws Exception { assertEquals(50, entryList.size()); } + @Test + public void testWithLuceneQueryAuthorDate() throws Exception { + List entryList = fetcher.performSearch("author:vigmond AND year:2021"); + entryList.forEach(entry -> entry.clearField(StandardField.ABSTRACT)); // Remove abstract due to copyright); + assertEquals(18, entryList.size()); + } + + @Test + public void testWithLuceneQueryAuthorDateRange() throws Exception { + List entryList = fetcher.performSearch("author:vigmond AND year-range:2020-2021"); + entryList.forEach(entry -> entry.clearField(StandardField.ABSTRACT)); // Remove abstract due to copyright); + assertEquals(28, entryList.size()); + } + @Test public void testInvalidSearchTerm() throws Exception { assertEquals(Optional.empty(), fetcher.performSearchById("this.is.a.invalid.search.term.for.the.medline.fetcher")); diff --git a/src/test/java/org/jabref/logic/importer/fetcher/transformers/IEEEQueryTransformerTest.java b/src/test/java/org/jabref/logic/importer/fetcher/transformers/IEEEQueryTransformerTest.java index 3a9e6cd275e..b9673370292 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/transformers/IEEEQueryTransformerTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/transformers/IEEEQueryTransformerTest.java @@ -39,7 +39,7 @@ public String getTitlePrefix() { } @Override - public void convertJournalField() throws Exception { + public void convertJournalFieldPrefix() throws Exception { IEEEQueryTransformer transformer = getTransformer(); String queryString = "journal:Nature"; diff --git a/src/test/java/org/jabref/logic/importer/fetcher/transformers/InfixTransformerTest.java b/src/test/java/org/jabref/logic/importer/fetcher/transformers/InfixTransformerTest.java index 70088f66604..c27584fa1b8 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/transformers/InfixTransformerTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/transformers/InfixTransformerTest.java @@ -19,16 +19,24 @@ public abstract class InfixTransformerTest { * Example in the case of ':': "author:" */ - protected abstract String getAuthorPrefix(); + protected String getAuthorPrefix() { + return ""; + } - protected abstract String getUnFieldedPrefix(); + protected String getUnFieldedPrefix() { + return ""; + } - protected abstract String getJournalPrefix(); + protected String getJournalPrefix() { + return ""; + } - protected abstract String getTitlePrefix(); + protected String getTitlePrefix() { + return ""; + } @Test - public void convertAuthorField() throws Exception { + public void convertAuthorFieldPrefix() throws Exception { String queryString = "author:\"Igor Steinmacher\""; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); @@ -37,7 +45,7 @@ public void convertAuthorField() throws Exception { } @Test - public void convertUnFieldedTerm() throws Exception { + public void convertUnFieldedTermPrefix() throws Exception { String queryString = "\"default value\""; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); @@ -46,7 +54,7 @@ public void convertUnFieldedTerm() throws Exception { } @Test - public void convertExplicitUnFieldedTerm() throws Exception { + public void convertExplicitUnFieldedTermPrefix() throws Exception { String queryString = "default:\"default value\""; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); @@ -55,7 +63,7 @@ public void convertExplicitUnFieldedTerm() throws Exception { } @Test - public void convertJournalField() throws Exception { + public void convertJournalFieldPrefix() throws Exception { String queryString = "journal:Nature"; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); @@ -70,7 +78,7 @@ public void convertJournalField() throws Exception { public abstract void convertYearRangeField() throws Exception; @Test - public void convertMultipleValuesWithTheSameField() throws Exception { + public void convertMultipleValuesWithTheSameFieldPrefix() throws Exception { String queryString = "author:\"Igor Steinmacher\" author:\"Christoph Treude\""; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); @@ -79,7 +87,7 @@ public void convertMultipleValuesWithTheSameField() throws Exception { } @Test - public void groupedOperations() throws Exception { + public void groupedOperationsPrefix() throws Exception { String queryString = "(author:\"Igor Steinmacher\" OR author:\"Christoph Treude\" AND author:\"Christoph Freunde\") AND title:test"; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); @@ -88,7 +96,7 @@ public void groupedOperations() throws Exception { } @Test - public void notOperator() throws Exception { + public void notOperatorPrefix() throws Exception { String queryString = "!(author:\"Igor Steinmacher\" OR author:\"Christoph Treude\")"; QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); diff --git a/src/test/java/org/jabref/logic/importer/fetcher/transformers/SuffixTransformerTest.java b/src/test/java/org/jabref/logic/importer/fetcher/transformers/SuffixTransformerTest.java new file mode 100644 index 00000000000..31b3b2239a6 --- /dev/null +++ b/src/test/java/org/jabref/logic/importer/fetcher/transformers/SuffixTransformerTest.java @@ -0,0 +1,94 @@ +package org.jabref.logic.importer.fetcher.transformers; + +import java.util.Optional; + +import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; +import org.apache.lucene.queryparser.flexible.standard.parser.StandardSyntaxParser; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test Interface for all transformers that use suffix notation for their logical binary operators + */ +public abstract class SuffixTransformerTest { + + protected abstract T getTransformer(); + + protected abstract String getAuthorSuffix(); + + protected abstract String getUnFieldedSuffix(); + + protected abstract String getJournalSuffix(); + + protected abstract String getTitleSuffix(); + + @Test + public void convertAuthorFieldSuffix() throws Exception { + String queryString = "author:\"Igor Steinmacher\""; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of("\"Igor Steinmacher\"" + getAuthorSuffix()); + assertEquals(expected, searchQuery); + } + + @Test + public void convertUnFieldedTermSuffix() throws Exception { + String queryString = "\"default value\""; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of(queryString + getUnFieldedSuffix()); + assertEquals(expected, searchQuery); + } + + @Test + public void convertExplicitUnFieldedTermSuffix() throws Exception { + String queryString = "default:\"default value\""; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of("\"default value\"" + getUnFieldedSuffix()); + assertEquals(expected, searchQuery); + } + + @Test + public void convertJournalFieldSuffix() throws Exception { + String queryString = "journal:Nature"; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of("Nature" + getJournalSuffix()); + assertEquals(expected, searchQuery); + } + + @Test + public abstract void convertYearField() throws Exception; + + @Test + public abstract void convertYearRangeField() throws Exception; + + @Test + public void convertMultipleValuesWithTheSameSuffix() throws Exception { + String queryString = "author:\"Igor Steinmacher\" author:\"Christoph Treude\""; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of("\"Igor Steinmacher\"" + getAuthorSuffix() + getTransformer().getLogicalAndOperator() + "\"Christoph Treude\"" + getAuthorSuffix()); + assertEquals(expected, searchQuery); + } + + @Test + public void groupedOperationsSuffix() throws Exception { + String queryString = "(author:\"Igor Steinmacher\" OR author:\"Christoph Treude\" AND author:\"Christoph Freunde\") AND title:test"; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of("(" + "\"Igor Steinmacher\"" + getAuthorSuffix() + getTransformer().getLogicalOrOperator() + "(" + "\"Christoph Treude\"" + getAuthorSuffix() + getTransformer().getLogicalAndOperator() + "\"Christoph Freunde\"" + getAuthorSuffix() + "))" + getTransformer().getLogicalAndOperator() + "test" + getTitleSuffix()); + assertEquals(expected, searchQuery); + } + + @Test + public void notOperatorSufix() throws Exception { + String queryString = "!(author:\"Igor Steinmacher\" OR author:\"Christoph Treude\")"; + QueryNode luceneQuery = new StandardSyntaxParser().parse(queryString, AbstractQueryTransformer.NO_EXPLICIT_FIELD); + Optional searchQuery = getTransformer().transformLuceneQuery(luceneQuery); + Optional expected = Optional.of(getTransformer().getLogicalNotOperator() + "(" + "\"Igor Steinmacher\"" + getAuthorSuffix() + getTransformer().getLogicalOrOperator() + "\"Christoph Treude\")" + getAuthorSuffix()); + assertEquals(expected, searchQuery); + } +}