diff --git a/.github/workflows/check-links.yaml b/.github/workflows/check-links.yaml deleted file mode 100644 index d570d9cb07e..00000000000 --- a/.github/workflows/check-links.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Check external href links in the documentation - -on: - schedule: - # Run on the first of each month at 9:00 AM (See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07) - - cron: "0 9 1 * *" - workflow_dispatch: - -jobs: - markdown-link-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - show-progress: 'false' - - uses: gaurav-nelson/github-action-markdown-link-check@v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'no' - config-file: 'mlc_config.json' - folder-path: 'docs/' - file-path: './README.md' diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml new file mode 100644 index 00000000000..a121d295643 --- /dev/null +++ b/.github/workflows/check-links.yml @@ -0,0 +1,35 @@ +name: Check external href links in the documentation + +on: + push: + paths: + - '.github/workflows/check-links.yml' + - '**/*.md' + schedule: + # Run on the first of each month at 9:00 AM (See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07) + - cron: "0 9 1 * *" + workflow_dispatch: + +concurrency: + group: "${{ github.workflow }}-${{ github.head_ref }}" + cancel-in-progress: true + +jobs: + lychee: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + show-progress: 'false' + - name: Restore lychee cache + uses: actions/cache@v3 + with: + path: .lycheecache + key: cache-lychee-${{ github.sha }} + restore-keys: cache-lychee- + - name: Link Checker + id: lychee + uses: lycheeverse/lychee-action@v1.8.0 + with: + fail: true + args: --max-concurrency 1 --cache --no-progress --exclude-all-private './**/*.md' diff --git a/.github/workflows/cleanup_pr.yml b/.github/workflows/cleanup-pr.yml similarity index 100% rename from .github/workflows/cleanup_pr.yml rename to .github/workflows/cleanup-pr.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 03914a7cbb1..9f1022654ff 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -182,8 +182,8 @@ jobs: cat heylogs.txt # exit 1 in case of error - # We have 2 "valid" issues in CHANGELOG.md - grep -q "2 problems" heylogs.txt || exit 1 + # We have 1 "valid" issue in CHANGELOG.md + grep -q "1 problem" heylogs.txt || exit 1 - name: Add comment on pull request if: ${{ failure() }} uses: thollander/actions-comment-pull-request@v2 @@ -304,6 +304,7 @@ jobs: steps: - name: Check secrets presence id: checksecrets + if: github.ref == 'refs/heads/main' shell: bash run: | if [ "$CODECOV_TOKEN" == "" ]; then @@ -312,25 +313,31 @@ jobs: echo "secretspresent=YES" >> $GITHUB_OUTPUT fi env: - SNAPCRAFT_LOGIN_FILE: ${{ secrets.CODECOV_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - name: Checkout source + if: github.ref == 'refs/heads/main' uses: actions/checkout@v4 with: submodules: 'true' show-progress: 'false' - name: Set up JDK + if: github.ref == 'refs/heads/main' uses: actions/setup-java@v3 with: java-version: 21.0.1 distribution: 'liberica' cache: 'gradle' - name: Update test coverage metrics - if: steps.checksecrets.outputs.secretspresent == 'YES' - run: xvfb-run --auto-servernum ./gradlew jacocoTestReport && bash <(curl -s https://codecov.io/bash); + if: (github.ref == 'refs/heads/main') && (steps.checksecrets.outputs.secretspresent == 'YES') + run: xvfb-run --auto-servernum ./gradlew jacocoTestReport env: CI: "true" CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} DBMS: "postgresql" + - uses: codecov/codecov-action@v3 + if: (github.ref == 'refs/heads/main') && (steps.checksecrets.outputs.secretspresent == 'YES') + with: + token: ${{ secrets.CODECOV_TOKEN }} # This is https://github.com/marketplace/actions/gradle-wrapper-validation # It ensures that the jar file is from gradle and not by a strange third party. gradlevalidation: diff --git a/.gitignore b/.gitignore index 72603d9dc08..28c62cbe9f0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ src/main/gen/ src/main/generated/ src-gen/ +.lycheecache + # generated by https://plugins.jetbrains.com/plugin/15991-plantuml-diagram-generator *.puml diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 00000000000..8d3f2072f17 --- /dev/null +++ b/.lycheeignore @@ -0,0 +1,14 @@ +https://arxiv.org/ +https://contribute.jabref.org/ +https://donations.jabref.org/ +https://pubs.acs.org/ +https://web.archive.org/ +https://www.researchgate.net/privacy-policy +https://www.sciencedirect.com/ + +https://github.com/koppor/jabref/issue +https://github.com/koppor/jabref/pull +https://github.com/JabRef/jabref/issue +https://github.com/JabRef/jabref/pull + +0005-example.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e287ab32a7..d36c03d2576 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,20 +11,27 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Added -- We integrated predatory journal checking as part of the Integrity Checker based on the [check-bib-for-predatory](https://github.com/CfKu/check-bib-for-predatory). [koppor#348](https://github.com/koppor/jabref/issues/348) +- We added a scite.ai tab in the entry editor that retrieves 'Smart Citation' tallies for citations that have a DOI. [koppor#375](https://github.com/koppor/jabref/issues/375) - We added a dropdown menu to let users change the reference library during AUX file import. [#10472](https://github.com/JabRef/jabref/issues/10472) - We added a button to let users reset the cite command to the default value. [#10569](https://github.com/JabRef/jabref/issues/10569) +- We added the option to use System Preference for Light/Dark Theme [#8729](https://github.com/JabRef/jabref/issues/8729). +- We added [scholar.archive.org](https://scholar.archive.org/) as a new fetcher. [#10498](https://github.com/JabRef/jabref/issues/10498) +- We integrated predatory journal checking as part of the Integrity Checker based on the [check-bib-for-predatory](https://github.com/CfKu/check-bib-for-predatory). [koppor#348](https://github.com/koppor/jabref/issues/348) ### Changed - We moved the location of the 'Open only one instance of JabRef' preference option from "Network" to "General". [#9306](https://github.com/JabRef/jabref/issues/9306) - The two previews in the change resolver dialog now have their scrollbars synchronized. [#9576](https://github.com/JabRef/jabref/issues/9576). - We changed the setting of the keyword separator to accept a single character only. [#177](https://github.com/koppor/jabref/issues/177) +- We replaced "SearchAll" in Web Search by "Search Selected". [#10556](https://github.com/JabRef/jabref/issues/10556) +- Short DOI formatter now checks, if the value is already formatted. If so, it returns the value instead of calling the ShortDOIService again. [#10589](https://github.com/JabRef/jabref/issues/10589) +- We upgraded to JavaFX 21.0.1. As a consequence JabRef requires now macOS 11 or later and GTK 3.8 or later on Linux [10627](https://github.com/JabRef/jabref/pull/10627). ### Fixed -- We fixed an issue where the added protected term has unwanted leading and trailing whitespaces, where the formatted text has unwanted empty brackets and where the word at the cursor in the textbox can be added to the list. [#10415](https://github.com/JabRef/jabref/issues/10415). +- We fixed an issue where the added protected term has unwanted leading and trailing whitespaces, where the formatted text has unwanted empty brackets and where the word at the cursor in the textbox can be added to the list. [#10415](https://github.com/JabRef/jabref/issues/10415) - We fixed an issue where in the merge dialog the file field of entries was not correctly merged when the first and second entry both contained values inside the file field. [#10572](https://github.com/JabRef/jabref/issues/10572) +- We fixed some small inconsistencies in the user interface. [#10507](https://github.com/JabRef/jabref/issues/10507) [#10458](https://github.com/JabRef/jabref/issues/10458) ### Removed @@ -91,7 +98,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added "Attach file from URL" to right-click context menu to download and store a file with the reference library. [#9646](https://github.com/JabRef/jabref/issues/9646) - We enabled updating an existing entry with data from InspireHEP. [#9351](https://github.com/JabRef/jabref/issues/9351) - We added a fetcher for the Bibliotheksverbund Bayern (experimental). [#9641](https://github.com/JabRef/jabref/pull/9641) -- We added support for more biblatex date formats for parsing dates. [#2753](https://github.com/JabRef/issues/2753) +- We added support for more biblatex date formats for parsing dates. [#2753](https://github.com/JabRef/jabref/issues/2753) - We added support for multiple languages for exporting to and importing references from MS Office. [#9699](https://github.com/JabRef/jabref/issues/9699) - We enabled scrolling in the groups list when dragging a group on another group. [#2869](https://github.com/JabRef/jabref/pull/2869) - We added the option to automatically download online files when a new entry is created from an existing ID (e.g., DOI). The option can be disabled in the preferences under "Import and Export". [#9756](https://github.com/JabRef/jabref/issues/9756) @@ -685,7 +692,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We fixed an issue with toggle of special fields does not work for sorted entries [#7016](https://github.com/JabRef/jabref/issues/7016) - We fixed an issue with the default path of external application. [#7641](https://github.com/JabRef/jabref/issues/7641) - We fixed an issue where urls must be embedded in a style tag when importing EndNote style Xml files. Now it can parse url with or without a style tag. [#6199](https://github.com/JabRef/jabref/issues/6199) -- We fixed an issue where the article title with colon fails to download the arXiv link (pdf file). [#7660](https://github.com/JabRef/issues/7660) +- We fixed an issue where the article title with colon fails to download the arXiv link (pdf file). [#7660](https://github.com/JabRef/jabref/issues/7660) - We fixed an issue where the keybinding for delete entry did not work on the main table [7580](https://github.com/JabRef/jabref/pull/7580) - We fixed an issue where the RFC fetcher is not compatible with the draft [7305](https://github.com/JabRef/jabref/issues/7305) - We fixed an issue where duplicate files (both file names and contents are the same) is downloaded and add to linked files [#6197](https://github.com/JabRef/jabref/issues/6197) @@ -787,7 +794,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Added - We added a new fetcher to enable users to search mEDRA DOIs [#6602](https://github.com/JabRef/jabref/issues/6602) -- We added a new fetcher to enable users to search "[Collection of Computer Science Bibliographies](https://liinwww.ira.uka.de/bibliography/index.html)". [#6638](https://github.com/JabRef/jabref/issues/6638) +- We added a new fetcher to enable users to search "[Collection of Computer Science Bibliographies](https://en.wikipedia.org/wiki/Collection_of_Computer_Science_Bibliographies)". [#6638](https://github.com/JabRef/jabref/issues/6638) - We added default values for delimiters in Add Subgroup window [#6624](https://github.com/JabRef/jabref/issues/6624) - We improved responsiveness of general fields specification dialog window. [#6604](https://github.com/JabRef/jabref/issues/6604) - We added support for importing ris file and load DOI [#6530](https://github.com/JabRef/jabref/issues/6530) @@ -880,7 +887,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We fixed an issue about duplicated group color indicators [#6175](https://github.com/JabRef/jabref/issues/6175) - We fixed an issue where entries with the entry type Misc from an imported aux file would not be saved correctly to the bib file on disk [#6405](https://github.com/JabRef/jabref/issues/6405) - We fixed an issue where percent sign ('%') was not formatted properly by the HTML formatter [#6753](https://github.com/JabRef/jabref/issues/6753) -- We fixed an issue with the [SAO/NASA Astrophysics Data System](https://docs.jabref.org/collect/import-using-online-bibliographic-database/ads) fetcher where `\textbackslash` appeared at the end of the abstract. +- We fixed an issue with the [SAO/NASA Astrophysics Data System](https://docs.jabref.org/collect/add-entry-using-an-id#sao-nasa-a-ds) fetcher where `\textbackslash` appeared at the end of the abstract. - We fixed an issue with the Science Direct fetcher where PDFs could not be downloaded. Fixes [#5860](https://github.com/JabRef/jabref/issues/5860) - We fixed an issue with the Library of Congress importer. - We fixed the [link to the external libraries listing](https://github.com/JabRef/jabref/blob/master/external-libraries.md) in the about dialog @@ -890,7 +897,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We removed the option of the "enforce legal key". [#6295](https://github.com/JabRef/jabref/issues/6295) - We removed the obsolete `External programs / Open PDF` section in the preferences, as the default application to open PDFs is now set in the `Manage external file types` dialog. [#6130](https://github.com/JabRef/jabref/pull/6130) -- We removed the option to configure whether a `.bib.bak` file should be generated upon save. It is now always enabled. Documentation at . [#6092](https://github.com/JabRef/jabref/issues/6092) +- We removed the option to configure whether a `.bib.bak` file should be generated upon save. It is now always enabled. Documentation at . [#6092](https://github.com/JabRef/jabref/issues/6092) - We removed the built-in list of IEEE journal abbreviations using BibTeX strings. If you still want to use them, you have to download them separately from . ## [5.0] – 2020-03-06 @@ -1020,7 +1027,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Removed - We removed some obsolete notifications. [#5555](https://github.com/JabRef/jabref/issues/5555) -- We removed an internal step in the [ISBN-to-BibTeX fetcher](https://docs.jabref.org/import-using-publication-identifiers/isbntobibtex): The [ISBN to BibTeX Converter](https://manas.tungare.name/software/isbn-to-bibtex) by [@manastungare](https://github.com/manastungare) is not used anymore, because it is offline: "people using this tool have not been generating enough sales for Amazon." +- We removed an internal step in the [ISBN-to-BibTeX fetcher](https://docs.jabref.org/collect/add-entry-using-an-id#isbn): The [ISBN to BibTeX Converter](https://manas.tungare.name/software/isbn-to-bibtex) by [@manastungare](https://github.com/manastungare) is not used anymore, because it is offline: "people using this tool have not been generating enough sales for Amazon." - We removed the option to control the default drag and drop behaviour. You can use the modifier keys (like CtrL or Alt) instead. ## [5.0-alpha] – 2019-08-25 @@ -1053,7 +1060,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - Change default icon for groups to a circle because a colored version of the old icon was hard to distinguish from its black counterpart. - In the main table, the context menu appears now when you press the "context menu" button on the keyboard. [feature request in the forum](https://discourse.jabref.org/t/how-to-enable-keyboard-context-key-windows) - We added icons to the group side panel to quickly switch between `union` and `intersection` group view mode. [#3269](https://github.com/JabRef/jabref/issues/3269). -- We use `https` for [fetching from most online bibliographic database](https://docs.jabref.org/import-using-online-bibliographic-database). +- We use `https` for [fetching from most online bibliographic database](https://docs.jabref.org/collect/import-using-online-bibliographic-database). - We changed the default keyboard shortcuts for moving between entries when the entry editor is active to ̀alt + up/down. - Opening a new file now prompts the directory of the currently selected file, instead of the directory of the last opened file. - Window state is saved on close and restored on start. diff --git a/PRIVACY.md b/PRIVACY.md index d7a1ca68b48..91df8163523 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -46,7 +46,7 @@ These third-party services are the following: | [arXiv.org](https://arxiv.org/) | | | [Bibliotheksverbund Bayern](https://www.bib-bvb.de/) | | | [Biodiversity Heritage Library](https://www.biodiversitylibrary.org/) | | -| [Collection of Computer Science Bibliographies](http://liinwww.ira.uka.de/) | **currently unavailable**, offline | +| [Collection of Computer Science Bibliographies](https://en.wikipedia.org/wiki/Collection_of_Computer_Science_Bibliographies) | **currently unavailable**, offline | | [CrossRef](https://www.crossref.org/) | | | [dblp](https://dblp.uni-trier.de/) | | | [Directory of Open Access Books](https://www.doabooks.org/) | | @@ -62,7 +62,7 @@ These third-party services are the following: | [Library of Congress](https://lccn.loc.gov/) | | | [National Library of Medicine](https://www.ncbi.nlm.nih.gov/) | | | [MathSciNet](http://www.ams.org/mathscinet) | | -| [mEDRA](https://medra.org/) | | +| [mEDRA](https://www.medra.org/) | | | [Mr. DLib](https://mr-dlib.org/) [1] | | | [Openlibrary](https://openlibrary.org) | | | [ResearchGate](https://www.researchgate.net/) | | diff --git a/build.gradle b/build.gradle index 4646a32c645..e573693b08f 100644 --- a/build.gradle +++ b/build.gradle @@ -101,7 +101,7 @@ dependencyLocking { } javafx { - version = "20.0.2" + version = "21.0.1" modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.web', 'javafx.swing' ] } @@ -172,16 +172,17 @@ dependencies { implementation 'com.github.sialcasa.mvvmFX:mvvmfx-validation:f195849ca9' //jitpack implementation 'de.saxsys:mvvmfx:1.8.0' implementation('com.tobiasdiez:easybind:2.2.1-SNAPSHOT') - implementation 'org.fxmisc.flowless:flowless:0.7.1' + implementation 'org.fxmisc.flowless:flowless:0.7.2' implementation 'org.fxmisc.richtext:richtextfx:0.11.1' - implementation (group: 'com.dlsc.gemsfx', name: 'gemsfx', version: '1.84.0') { + implementation (group: 'com.dlsc.gemsfx', name: 'gemsfx', version: '1.90.0') { exclude module: 'javax.inject' // Split package, use only jakarta.inject exclude group: 'org.apache.logging.log4j' } - implementation 'org.controlsfx:controlsfx:11.1.2' + implementation 'org.controlsfx:controlsfx:11.2.0' + implementation 'com.github.Dansoftowner:jSystemThemeDetector:3.6' - implementation 'org.jsoup:jsoup:1.16.1' + implementation 'org.jsoup:jsoup:1.16.2' implementation 'com.konghq:unirest-java:3.14.5' implementation 'org.slf4j:slf4j-api:2.0.9' @@ -235,14 +236,14 @@ dependencies { // implementation 'org.glassfish.jersey.media:jersey-media-json-gson:3.1.1' testImplementation 'io.github.classgraph:classgraph:4.8.163' - testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0' + testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1' testImplementation 'org.junit.platform:junit-platform-launcher:1.10.0' testImplementation 'org.mockito:mockito-core:5.6.0' testImplementation 'org.xmlunit:xmlunit-core:2.9.1' testImplementation 'org.xmlunit:xmlunit-matchers:2.9.1' testRuntimeOnly 'com.tngtech.archunit:archunit-junit5-engine:1.1.0' - testImplementation 'com.tngtech.archunit:archunit-junit5-api:1.1.0' + testImplementation 'com.tngtech.archunit:archunit-junit5-api:1.2.0' testImplementation "org.testfx:testfx-core:4.0.16-alpha" testImplementation "org.testfx:testfx-junit5:4.0.16-alpha" testImplementation "org.hamcrest:hamcrest-library:2.2" @@ -252,7 +253,7 @@ dependencies { xjc group: 'org.glassfish.jaxb', name: 'jaxb-xjc', version: '3.0.2' xjc group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '3.0.2' - rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:latest.integration")) + rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:2.4.1")) rewrite("org.openrewrite.recipe:rewrite-static-analysis") rewrite("org.openrewrite.recipe:rewrite-logging-frameworks") rewrite("org.openrewrite.recipe:rewrite-testing-frameworks") diff --git a/buildres/LICENSE_with_Privacy.md b/buildres/LICENSE_with_Privacy.md index 41264b1efcc..291dd3e5f34 100644 --- a/buildres/LICENSE_with_Privacy.md +++ b/buildres/LICENSE_with_Privacy.md @@ -1,6 +1,6 @@ MIT License -Copyright © 2003-2021 [JabRef Authors](https://github.com/JabRef/jabref/blob/master/AUTHORS) +Copyright © 2003-2021 JabRef Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -89,7 +89,7 @@ Service;Privacy Policy [arXiv.org](https://arxiv.org/); [Bibliotheksverbund Bayern](https://www.bib-bvb.de/); [Biodiversity Heritage Library](https://www.biodiversitylibrary.org/); -[Collection of Computer Science Bibliographies](http://liinwww.ira.uka.de/);**currently unavailable**, offline +[Collection of Computer Science Bibliographies](https://en.wikipedia.org/wiki/Collection_of_Computer_Science_Bibliographies);**currently unavailable**, offline [CrossRef](https://www.crossref.org/); [dblp](https://dblp.uni-trier.de/); [Directory of Open Access Books](https://www.doabooks.org/); @@ -105,7 +105,7 @@ Service;Privacy Policy [Library of Congress](https://lccn.loc.gov/); [National Library of Medicine](https://www.ncbi.nlm.nih.gov/); [MathSciNet](http://www.ams.org/mathscinet); -[mEDRA](https://medra.org/); +[mEDRA](https://www.medra.org/); [Mr. DLib](https://mr-dlib.org/) [1]; [Openlibrary](https://openlibrary.org); [ResearchGate](https://www.researchgate.net/); diff --git a/docs/code-howtos/IntelliJ.md b/docs/code-howtos/IntelliJ.md index 5cac3dac319..be1e13d611c 100644 --- a/docs/code-howtos/IntelliJ.md +++ b/docs/code-howtos/IntelliJ.md @@ -17,7 +17,7 @@ Did you know that [IntelliJ allows for reformatting selected code](https://www.j ## Show variable values in IntelliJ -1. Go to a test case (example: [`org.jabref.model.entry.BibEntryTest#settingTypeToNullThrowsException`](https://github.com/JabRef/jabref/blob/refine-intellij-howto/src/test/java/org/jabref/model/entry/BibEntryTest.java#L52-L52) +1. Go to a test case (example: [`org.jabref.model.entry.BibEntryTest#settingTypeToNullThrowsException`](https://github.com/JabRef/jabref/blob/main/src/test/java/org/jabref/model/entry/BibEntryTest.java#L52-L52) 2. Set the breakpoint to the first line 3. Execute the test 4. Go to the settings of the debugger and activate "Show Variable Values in Editor" and "Show Method Return Values" diff --git a/docs/code-howtos/index.md b/docs/code-howtos/index.md index fff2c645b44..eb11987445d 100644 --- a/docs/code-howtos/index.md +++ b/docs/code-howtos/index.md @@ -5,7 +5,7 @@ has_children: true # Code Howtos This page provides some development support in the form of howtos. -See also [High Level Documentation](../getting-into-thecode/high-level-documentation.md). +See also [High Level Documentation](../getting-into-the-code/high-level-documentation.md). ## Generic code how tos diff --git a/docs/code-howtos/javafx.md b/docs/code-howtos/javafx.md index c045b12fc12..2dfb8514351 100644 --- a/docs/code-howtos/javafx.md +++ b/docs/code-howtos/javafx.md @@ -62,7 +62,7 @@ The goal of the MVVM architecture is to separate the state/behavior from the app The only class which access model and logic classes is the ViewModel. Controller and View have only access the ViewModel and never the backend. The ViewModel does not know the Controller or View. -More details about the MVVM pattern can be found in [an article by Microsoft](https://msdn.microsoft.com/en-us/magazine/dd419663.aspx) and in [an article focusing on the implementation with JavaFX](http://blog.buildpath.de/javafx-decouple-the-view-and-its-behavior-to-create-a-testable-ui/). +More details about the MVVM pattern can be found in [an article by Microsoft](https://msdn.microsoft.com/en-us/magazine/dd419663.aspx) and in [an article focusing on the implementation with JavaFX](https://web.archive.org/web/20140825151304/http://blog.buildpath.de/javafx-decouple-the-view-and-its-behavior-to-create-a-testable-ui/). ## An example diff --git a/docs/code-howtos/openoffice/code-reorganization.md b/docs/code-howtos/openoffice/code-reorganization.md index c9c37fe47d8..d7bd01a1244 100644 --- a/docs/code-howtos/openoffice/code-reorganization.md +++ b/docs/code-howtos/openoffice/code-reorganization.md @@ -29,15 +29,15 @@ Why * `OOListUtil`: some utilities working on List * `uno` : helpers for various tasks via UNO.\ These are conceptually independent of JabRef code and logic. - * `ootext` : to separate decisions on the format of references and citation marks from the actual insertion into the document, the earlier method [OOUtil.insertOOFormattedTextAtCurrentLocation](https://github.com/JabRef/jabref/blob/475b2989ffa8ec61c3327c62ed8f694149f83220/src/main/java/org/jabref/logic/openoffice/OOUtil.java#L112) was extended to handle new tags that describe actions earlier done in code. - * This became [OOTextIntoOO.write](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/model/openoffice/ootext/OOTextIntoOO.java#L149) + * `ootext` : to separate decisions on the format of references and citation marks from the actual insertion into the document, the earlier method `OOUtil.insertOOFormattedTextAtCurrentLocation` was extended to handle new tags that describe actions earlier done in code. + * This became `OOTextIntoOO.write` * `(change)` Now all output to the document goes through this, not only those from Layout. This allows the citation markers and `jstyle:Title` to use these tags. * This allows some backward-compatible extensions to jstyle.\ - `(change)` [Added](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/style/OOBibStyle.java#L92) some extra keywords, in `{prefix}_MARKUP_BEFORE`, `{prefix}_MARKUP_AFTER` pairs to allow bracketing some parts of citation marks with text and/or open/close tag pairs. - * [OOFormat](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/model/openoffice/ootext/OOFormat.java) contains helpers to create the appropriate tags - * [OOText](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/model/openoffice/ootext/OOText.java) formalizes the distinction from `String`. I did not change `String` to `OOText` in old code, (in particular in OOStyle). + `(change)` Added some extra keywords, in `{prefix}_MARKUP_BEFORE`, `{prefix}_MARKUP_AFTER` pairs to allow bracketing some parts of citation marks with text and/or open/close tag pairs. + * `OOFormat` contains helpers to create the appropriate tags + * `OOText` formalizes the distinction from `String`. I did not change `String` to `OOText` in old code, (in particular in OOStyle). * `rangesort` : ordering objects that have an `XTextRange`, optionally with an extra integer to break ties. - * `RangeSort.partitionAndSortRanges` : since `XTextRangeCompare` can only compare `XTextRange` values in the same `XText`, we partition them accordingly and only sort within each partiion. + * `RangeSort.partitionAndSortRanges` : since `XTextRangeCompare` can only compare `XTextRange` values in the same `XText`, we partition them accordingly and only sort within each partition. * `RangeSortable` (interface), `RangeSortEntry` (implements) :\ When we replace `XTextRange` of citation marks in footnotes with the range of the footnote mark, multiple citation marks may be mapped to the same location. To preserve the order between these, `RangeSortable` allows this order to be indicated by returning appropriate indices from `getIndexInPosition` * `RangeSortVisual` : sort in top-to-bottom left-to-right order.\ @@ -61,12 +61,12 @@ At the core, * a list of citations (`citationsInStorageOrder`) * an identifier `CitationGroupId cgid` * this allows to refer to the group - * also used to associate the group to its citation markers location (outside the style part, in [Backend](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/backend/Backend52.java#L46)) + * also used to associate the group to its citation markers location (outside the style part, in `Backend52`) * `OODataModel dataModel` is here, in order to handle old (Jabref5.2) structure where pageInfo belonged to CitationGroup not Citation * `referenceMarkNameForLinking` is optional: can be used to crosslink to the citation marker from the bibliography. * `CitationGroups` represents the collection of citation groups.\ Processing starts with creating a `CitationGroups` instance from the data stored in the document. -* `CitedKey` represents a cited source, with ordered backreferences (using `CitationPath`) to the correponding citations. +* `CitedKey` represents a cited source, with ordered back references (using `CitationPath`) to the corresponding citations. * `CitedKeys` is just an order-preserving collection of `CitedKeys` that also supports lookup by `citationKey`. While producing citation markers, we also create a corresponding `CitedKeys` instance, and store it in `CitationGroups.bibliography`. This is already sorted, its entries have `uniqueLetter` or `number` assigned, but not converted to markup yet. Common processing steps: @@ -79,10 +79,11 @@ Common processing steps: We can create a `CitedKeys` instance (`bibliography`) according to this order. * For citations numbered in order of first appearance we number the sources and distribute the numbers to the corresponding citations. * For citations numbered in order of bibliography, we sort the bibliography, number, distribute. -* For author-year citations we have to decide on the letters `uniqueLetter` used to distinguish sources. This needs order of first appearance of the sources and recognizing clashing citation markers. This is done in logic, in [`OOProcessAuthorYearMarkers.createUniqueLetters()`](https://github.com/antalk2/jabref/blob/122d5133fa6c7b44245c5ba5600d398775718664/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java#L49) -* We also mark first appearance of each source ([`setIsFirstAppearanceOfSourceInCitations`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcessAuthorYearMarkers.java#L146)) +* For author-year citations we have to decide on the letters `uniqueLetter` used to distinguish sources. This needs order of first appearance of the sources and recognizing clashing citation markers. This is done in logic, in `OOProcessAuthorYearMarkers.createUniqueLetters()` +* We also mark first appearance of each source (`setIsFirstAppearanceOfSourceInCitations`) + +The entry point for this processing is: `OOProcess.produceCitationMarkers`. -The entry point for this processing is: [`OOProcess.produceCitationMarkers`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java#L69).\ It fills * each `CitationGroup.citationMarker` @@ -94,7 +95,7 @@ It fills * `StyleLoader` : not changed (knows about default styles) Used by GUI * `OOPreFormatter` : LaTeX code to unicode and OOText tags. (not changed) * `OOBibStyle` : is mostly concerned by loading/parsing jstyle files and presenting its pieces to the rest. Originally it also contains code to format numeric and author-year citation markers. - * Details of their new implementations are in [`OOBibStyleGetNumCitationMarker`](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetNumCitationMarker.java) and [`OOBibStyleGetCitationMarker`](https://github.com/antalk2/jabref/blob/improve-reversibility-rebased-03/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java) + * Details of their new implementations are in `OOBibStyleGetNumCitationMarker` and `OOBibStyleGetCitationMarker` * The new implementations * support pageInfo for each citation * support unresolved citations @@ -106,7 +107,7 @@ It fills * `CitationMarkerNumericBibEntry` * `CitationMarkerNormEntry`\ describe their expected input entries. -* [`OOProcess.produceCitationMarkers`](https://github.com/antalk2/jabref/blob/fed0952cbdaf7a76bcb09b3db5ac48f34f5ca388/src/main/java/org/jabref/logic/openoffice/style/OOProcess.java#L69) is the main entry point for style application. Calls to specific implementations in `OOProcessCitationKeyMarkers`, `OOProcessNumericMarkers` and `OOProcessAuthorYearMarkers` according to jstyle flags. +* `OOProcess.produceCitationMarkers` is the main entry point for style application. Calls to specific implementations in `OOProcessCitationKeyMarkers`, `OOProcessNumericMarkers` and `OOProcessAuthorYearMarkers` according to jstyle flags. ## logic/backend diff --git a/docs/code-howtos/remote-storage.md b/docs/code-howtos/remote-storage.md index 0f845913aa5..01a402afc79 100644 --- a/docs/code-howtos/remote-storage.md +++ b/docs/code-howtos/remote-storage.md @@ -12,4 +12,4 @@ JabRef supports kinds of remote storage: The first one is the more modern approach allowing offline-work. The second approach makes use of the SQL features of databases and require direct online connections. -More details in [JabDrive](remote-storeage-jabdrive.md) and [SQL Storage](remote-storage-sql.md) respectively. +More details in [JabDrive](remote-storage-jabdrive.md) and [SQL Storage](remote-storage-sql.md) respectively. diff --git a/docs/code-howtos/tools.md b/docs/code-howtos/tools.md index c4e9853a21f..f2b344da05a 100644 --- a/docs/code-howtos/tools.md +++ b/docs/code-howtos/tools.md @@ -16,9 +16,9 @@ This page lists some software we consider useful. Here, we collect some helpful git hints -* [https://github.com/blog/2019-how-to-undo-almost-anything-with-git](https://github.com/blog/2019-how-to-undo-almost-anything-with-git) -* [https://github.com/RichardLitt/docs/blob/master/amending-a-commit-guide.md](https://github.com/RichardLitt/docs/blob/master/amending-a-commit-guide.md) -* awesome hints and tools regarding git: [https://github.com/dictcp/awesome-git](https://github.com/dictcp/awesome-git) +* +* [So you need to change your commit](https://github.com/RichardLitt/knowledge/blob/master/github/amending-a-commit-guide.md#so-you-need-to-change-your-commit) +* awesome hints and tools regarding git: ### Rebase everything as one commit on main diff --git a/docs/contributing.md b/docs/contributing.md index bd187bf1f3f..06451efcbc9 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -78,7 +78,7 @@ Actual :[Opens\ JabRef's\ Twitter\ page (src\main\java\org\jabref\gui\JabRefFr Add the above snippet to the English translation file located at `src/main/resources/l10n/JabRef_en.properties`. [Crowdin](https://crowdin.com/project/jabref) will automatically pick up the new string and add it to the other translations. -You can also directly run the specific test in your IDE. The test "LocalizationConsistencyTest" is placed under `src/test/java/org.jabref.logic.l10n/LocalizationConsistencyTest.java`. Find more information in the [JabRef developer docs](https://devdocs.jabref.org/getting-into-the-code/code-howtos#using-localization-correctly). +You can also directly run the specific test in your IDE. The test "LocalizationConsistencyTest" is placed under `src/test/java/org.jabref.logic.l10n/LocalizationConsistencyTest.java`. Find more information in the [JabRef developer docs](code-howtos/localization.md). #### When adding a library diff --git a/docs/decisions/0009-use-plain-junit5-for-testing.md b/docs/decisions/0009-use-plain-junit5-for-testing.md index 3d88c5989e3..5ca034a33cd 100644 --- a/docs/decisions/0009-use-plain-junit5-for-testing.md +++ b/docs/decisions/0009-use-plain-junit5-for-testing.md @@ -34,7 +34,7 @@ Chosen option: "Plain JUnit5", because comes out best \(see below\). ### Plain JUnit5 Homepage: -JabRef testing guidelines: +JabRef testing guidelines: <../testing.md> Example: diff --git a/docs/getting-into-the-code/development-strategy.md b/docs/getting-into-the-code/development-strategy.md index 8fddcd79b47..b58387ba1c8 100644 --- a/docs/getting-into-the-code/development-strategy.md +++ b/docs/getting-into-the-code/development-strategy.md @@ -12,7 +12,7 @@ To ensure high code-quality, * We follow the principles of [Effective Java](https://www.oreilly.com/library/view/effective-java-3rd/9780134686097/). * We use [Design Patterns](https://java-design-patterns.com/patterns/) when applicable. * We document our design decisions using the lightweight architectural decision records [MADR](https://adr.github.io/madr/). -* We review each external pull request by at least two [JabRef Core Developers](https://github.com/JabRef/jabref/blob/main/MAINTAINERS/README.md). +* We review each external pull request by at least two [JabRef Core Developers](https://github.com/JabRef/jabref/blob/main/MAINTAINERS). Read on about our automated quality checks at [Code Quality](../code-howtos/code-quality.md). @@ -35,7 +35,7 @@ Other branches are used for discussing improvements with the help of [pull reque ## How JabRef acquires contributors -* We participate in [Hacktoberfest](https://hacktoberfest.digitalocean.com). See [https://www.jabref.org/hacktoberfest/](https://www.jabref.org/hacktoberfest/) for details. +* We participate in [Hacktoberfest](https://www.hacktoberfest.com). * We participate in [Google Summer of Code](https://developers.google.com/open-source/gsoc/). ## Historical notes diff --git a/docs/teaching.md b/docs/teaching.md index dedc12bde3f..6c617826f50 100644 --- a/docs/teaching.md +++ b/docs/teaching.md @@ -21,7 +21,6 @@ By using JabRef as training object in exercises and labs, students can level-up implementation effort, testing effort, and "issue understanding effort". The latter category is important, because some issues are "quick wins" and others need thorough thinking. - In general, all issues of JabRef are free to take. Be aware that the difficulty of bugs and feature vary. For the brave, the [Bug Board](https://github.com/orgs/JabRef/projects/7) or the [Feature Board](https://github.com/JabRef/jabref/projects/6) provide other issue sources. @@ -34,7 +33,7 @@ By using JabRef as training object in exercises and labs, students can level-up 6. Students address review feedback 7. Students submit pull request 8. Code reviews by JabRef maintainers -9. Students address feedback and learn more about good coding practices by incoporating feedback +9. Students address feedback and learn more about good coding practices by incorporating feedback 10. Students update their pull request 11. Pull request is merged @@ -50,19 +49,19 @@ There is no special process for student contributions. We want to discuss it nev The process for accepting contributions is as below. The syntax is [BPMN](https://en.wikipedia.org/wiki/Business\_Process\_Model\_and\_Notation) modeled using [bpmn.io](https://bpmn.io). -[![process]()](https://github.com/JabRef/jabref/tree/ed275b62fe7dac57a086e43802e36deb93c63e31/docs/images/contribution-process-reviews.svg) +[![process](images/contribution-process-reviews.svg)](https://raw.githubusercontent.com/JabRef/jabref/main/docs/images/contribution-process-reviews.svg) In short, the contribution is **reviewed by two JabRef developers**. Typically, they have constructive feedback on their contribution. This means, that the contributors get comments on their contribution enabling them to level-up their coding skill. Incorporating improvements takes time, too. The benefit is two-fold: a) contributors improve their coding skills and b) JabRef's code quality improves. All in all, we ask to respect the aims of the JabRef team and to reserve time to incorporate the reviewer's comments. GitHub describes that in their page [Understanding the GitHub flow](https://guides.github.com/introduction/flow/): -[![GitHub flow]()](https://github.com/JabRef/jabref/tree/ed275b62fe7dac57a086e43802e36deb93c63e31/docs/images/github-flow.png) +[![GitHub flow](images/github-flow.png)](https://raw.githubusercontent.com/JabRef/jabref/main/docs/images/github-flow.png) ## Process for Java newcomers Newcomers contributing in the context of a university teaching experience are invited to follow the process described above. In case the capacity of the instructing university allows, we propose a three-step approach. First, the contributors prepare their contribution as usual. Then, they submit the pull request _to a separate repository_. There, the instructor reviews the pull request and provides feedback. This happens in a loop until the instructor shows the green light. Then, the pull request can be submitted to the main JabRef repository. This will help to reduce the load on the JabRef team and improve the quality of the initial pull request. -[![process with instructor]()](https://github.com/JabRef/jabref/tree/ed275b62fe7dac57a086e43802e36deb93c63e31/docs/images/contribution-process-reviews-with-instructor.svg) +[![process with instructor](images/contribution-process-reviews-with-instructor.svg)](https://raw.githubusercontent.com/JabRef/jabref/main/docs/images/contribution-process-reviews-with-instructor.svg) ## Past courses @@ -129,7 +128,7 @@ Course "Programming and Software Development" as part of the [BSc Software Engin Course [DD2480 Software Engineering Fundamentals](https://www.kth.se/student/kurser/kurs/DD2480?l=en) -* Summary: Groups of students from three to five persons experienced the whole software engineering process within a week: From the requirements specification to the final pull request. +* Summary: Groups of students from three to five persons experienced the whole software engineering process within a week: From the requirements' specification to the final pull request. * Successfully run in 2020 ### Portuguese diff --git a/external-libraries.md b/external-libraries.md index 6e68aa9bd68..2f06c5cdcf1 100644 --- a/external-libraries.md +++ b/external-libraries.md @@ -4,7 +4,7 @@ This document lists the fonts, icons, and libraries used by JabRef. This file is manually kept in sync with build.gradle and the binary jars contained in the lib/ directory. One can list all dependencies by using Gradle task `dependencyReport`. -It generates the file [build/reports/project/dependencies.txt](build/reports/project/dependencies.txt). +It generates the file `build/reports/project/dependencies.txt`. Below, there is a howto to generate the content at "Sorted list of runtime dependencies output by gradle". ## Legend @@ -155,6 +155,13 @@ URL: https://github.com/lemire/javaewah License: Apache-2.0 ``` +```yaml +Id: com.jthemedetecor.OsThemeDetector +Project: jSystemThemeDetector +URL: https://github.com/Dansoftowner/jSystemThemeDetector +License: Apache-2.0 +``` + ```yaml Id: com.konghq.unirest Project: Unirest for Java diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000000..ffc6ffe8716 --- /dev/null +++ b/lychee.toml @@ -0,0 +1 @@ +exclude_path = ["build/", "buildres/abbrv.jabref.org", "out/", "src/main/resources/csl-locales", "src/main/resources/csl-styles"] diff --git a/mlc_config.json b/mlc_config.json deleted file mode 100644 index e4ae50df899..00000000000 --- a/mlc_config.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "autohotkey.com" - }, - { - "pattern": "baeldung.com" - }, - { - "pattern": "^CONTRIBUTING\\.md" - }, - { - "pattern": "^https://codecov\\.io/" - }, - { - "pattern": "^https://dl\\.acm\\.org" - }, - { - "pattern": "^https://github\\.com" - }, - { - "pattern": "^https://.*\\.jabref\\.org" - }, - { - "pattern": "^https://sourcespy\\.com/.*" - }, - { - "pattern": "^http://purl\\.org/net/bibteXMP" - }, - { - "pattern": "tldrlegal.com" - }, - { - "pattern": "^https://web\\.archive\\.org" - }, - { - "pattern": "^https://www\\.slant\\.co/" - }, - { - "pattern": "^http://localhost" - }, - { - "pattern": "^https://demo.teamscale.com" - } - ] -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 56ee2eca620..70eb10b2914 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -140,4 +140,5 @@ requires org.antlr.antlr4.runtime; requires org.libreoffice.uno; requires de.saxsys.mvvmfx.validation; + requires com.jthemedetector; } diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 68f96eebf28..8aa35586865 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1447,3 +1447,8 @@ We want to have a look that matches our icons in the tool-bar */ .table-column .rotated > .label { -fx-content-display: graphic-only; } + +.customGenerateButton { + -fx-padding: 0.5em 2em; + -fx-min-width: 10em; +} diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index 6b4bb2f8f0a..238d80d7d17 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -88,6 +88,7 @@ public EntryTypeView(LibraryTab libraryTab, DialogService dialogService, Prefere }); Button btnGenerate = (Button) this.getDialogPane().lookupButton(generateButton); + btnGenerate.getStyleClass().add("customGenerateButton"); btnGenerate.textProperty().bind(EasyBind.map(viewModel.searchingProperty(), searching -> searching ? Localization.lang("Searching...") : Localization.lang("Generate"))); btnGenerate.disableProperty().bind(viewModel.idFieldValidationStatus().validProperty().not().or(viewModel.searchingProperty())); diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css index 4b2befd4dd3..fc3a3446644 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css @@ -146,3 +146,21 @@ .description { -fx-font-style: italic; } + +.scite-tallies-label { + -fx-font-size: 1.5em; + -fx-font-weight: bold; +} + +.scite-error-box { + -fx-padding: 30 0 0 30; +} +.scite-message-box { + -fx-padding: 30 0 0 30; +} + +.scite-error-label { + -fx-font-size: 1.5em; + -fx-font-weight: bold; + -fx-text-fill: -fx-accent; +} diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index 3d42d562a26..7ee6f1b6968 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -273,6 +273,7 @@ private List createTabs() { entryEditorTabList.remove(RelatedArticlesTab.NAME); entryEditorTabList.remove(LatexCitationsTab.NAME); entryEditorTabList.remove(FulltextSearchResultsTab.NAME); + entryEditorTabList.remove(SciteTab.NAME); entryEditorTabList.remove("Comments"); // Then show the remaining configured for (Map.Entry> tab : entryEditorTabList.entrySet()) { @@ -302,6 +303,8 @@ private List createTabs() { entryEditorTabs.add(new FulltextSearchResultsTab(stateManager, preferencesService, dialogService, taskExecutor)); + entryEditorTabs.add(new SciteTab(preferencesService, taskExecutor, dialogService)); + return entryEditorTabs; } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java index 73431acb78d..c2afea3b0af 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java @@ -47,6 +47,7 @@ public static JournalPopupEnabled fromString(String status) { private final DoubleProperty dividerPosition; private final BooleanProperty autoLinkFiles; private final ObjectProperty enablementStatus; + private final BooleanProperty shouldShowSciteTab; public EntryEditorPreferences(Map> entryEditorTabList, Map> defaultEntryEditorTabList, @@ -58,7 +59,8 @@ public EntryEditorPreferences(Map> entryEditorTabList, boolean allowIntegerEditionBibtex, double dividerPosition, boolean autolinkFilesEnabled, - JournalPopupEnabled journalPopupEnabled) { + JournalPopupEnabled journalPopupEnabled, + boolean showSciteTab) { this.entryEditorTabList = new SimpleMapProperty<>(FXCollections.observableMap(entryEditorTabList)); this.defaultEntryEditorTabList = new SimpleMapProperty<>(FXCollections.observableMap(defaultEntryEditorTabList)); @@ -71,6 +73,7 @@ public EntryEditorPreferences(Map> entryEditorTabList, this.dividerPosition = new SimpleDoubleProperty(dividerPosition); this.autoLinkFiles = new SimpleBooleanProperty(autolinkFilesEnabled); this.enablementStatus = new SimpleObjectProperty<>(journalPopupEnabled); + this.shouldShowSciteTab = new SimpleBooleanProperty(showSciteTab); } public ObservableMap> getEntryEditorTabs() { @@ -196,4 +199,16 @@ public ObjectProperty enableJournalPopupProperty() { public void setEnableJournalPopup(JournalPopupEnabled journalPopupEnabled) { this.enablementStatus.set(journalPopupEnabled); } + + public boolean shouldShowSciteTab() { + return this.shouldShowSciteTab.get(); + } + + public BooleanProperty shouldShowLSciteTabProperty() { + return this.shouldShowSciteTab; + } + + public void setShouldShowSciteTab(boolean shouldShowSciteTab) { + this.shouldShowSciteTab.set(shouldShowSciteTab); + } } diff --git a/src/main/java/org/jabref/gui/entryeditor/SciteTab.java b/src/main/java/org/jabref/gui/entryeditor/SciteTab.java new file mode 100644 index 00000000000..2033a945a5c --- /dev/null +++ b/src/main/java/org/jabref/gui/entryeditor/SciteTab.java @@ -0,0 +1,131 @@ +package org.jabref.gui.entryeditor; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import javafx.geometry.HPos; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; + +import org.jabref.gui.DialogService; +import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; +import org.jabref.preferences.PreferencesService; + +import com.tobiasdiez.easybind.EasyBind; +import org.controlsfx.control.HyperlinkLabel; + +public class SciteTab extends EntryEditorTab { + + public static final String NAME = "Scite"; + public static final String SCITE_REPORTS_URL_BASE = "https://scite.ai/reports/"; + + private final GridPane sciteResultsPane; + private final ProgressIndicator progressIndicator; + private final SciteTabViewModel viewModel; + private final PreferencesService preferencesService; + private final DialogService dialogService; + + public SciteTab(PreferencesService preferencesService, TaskExecutor taskExecutor, DialogService dialogService) { + this.preferencesService = preferencesService; + this.viewModel = new SciteTabViewModel(preferencesService, taskExecutor); + this.dialogService = dialogService; + this.sciteResultsPane = new GridPane(); + this.progressIndicator = new ProgressIndicator(); + setText(NAME); + setTooltip(new Tooltip(Localization.lang("Search scite.ai for Smart Citations"))); + setSciteResultsPane(); + } + + private void setSciteResultsPane() { + progressIndicator.setMaxSize(100, 100); + sciteResultsPane.add(progressIndicator, 0, 0); + + ColumnConstraints column = new ColumnConstraints(); + column.setPercentWidth(100); + column.setHalignment(HPos.CENTER); + + sciteResultsPane.getColumnConstraints().setAll(column); + sciteResultsPane.setId("scitePane"); + setContent(sciteResultsPane); + + EasyBind.subscribe(viewModel.statusProperty(), status -> { + sciteResultsPane.getChildren().clear(); + switch (status) { + case IN_PROGRESS -> + sciteResultsPane.add(progressIndicator, 0, 0); + case FOUND -> + viewModel.getCurrentResult().ifPresent(result -> sciteResultsPane.add(getTalliesPane(result), 0, 0)); + case ERROR -> + sciteResultsPane.add(getErrorPane(), 0, 0); + } + }); + } + + @Override + public boolean shouldShow(BibEntry entry) { + return viewModel.shouldShow(); + } + + @Override + protected void bindToEntry(BibEntry entry) { + viewModel.bindToEntry(entry); + } + + private VBox getErrorPane() { + Label titleLabel = new Label(Localization.lang("Error")); + titleLabel.getStyleClass().add("scite-error-label"); + Text errorMessageText = new Text(viewModel.searchErrorProperty().get()); + VBox errorMessageBox = new VBox(30, titleLabel, errorMessageText); + errorMessageBox.getStyleClass().add("scite-error-box"); + return errorMessageBox; + } + + private VBox getTalliesPane(SciteTallyModel tallModel) { + Label titleLabel = new Label(Localization.lang("Tallies for %0", tallModel.doi())); + titleLabel.getStyleClass().add("scite-tallies-label"); + Text message = new Text(String.format("Total Citations: %d\nSupporting: %d\nContradicting: %d\nMentioning: %d\nUnclassified: %d\nCiting Publications: %d", + tallModel.total(), + tallModel.supporting(), + tallModel.contradicting(), + tallModel.mentioning(), + tallModel.unclassified(), + tallModel.citingPublications() + )); + + String url = SCITE_REPORTS_URL_BASE + URLEncoder.encode(tallModel.doi(), StandardCharsets.UTF_8); + VBox messageBox = getMessageBox(url, titleLabel, message); + messageBox.getStyleClass().add("scite-message-box"); + return messageBox; + } + + private VBox getMessageBox(String url, Label titleLabel, Text message) { + HyperlinkLabel link = new HyperlinkLabel(Localization.lang("See full report at [%0]", url)); + link.setOnAction(event -> { + if (event.getSource() instanceof Hyperlink) { + var filePreferences = preferencesService.getFilePreferences(); + try { + JabRefDesktop.openBrowser(url, filePreferences); + } catch (IOException ioex) { + // Can't throw a checked exception from here, so display a message to the user instead. + dialogService.showErrorDialogAndWait( + "An error occurred opening web browser", + "JabRef was unable to open a web browser for link:\n\n" + url + "\n\nError Message:\n\n" + ioex.getMessage(), + ioex + ); + } + } + }); + + return new VBox(30, titleLabel, message, link); + } +} diff --git a/src/main/java/org/jabref/gui/entryeditor/SciteTabViewModel.java b/src/main/java/org/jabref/gui/entryeditor/SciteTabViewModel.java new file mode 100644 index 00000000000..f05ab1ac94b --- /dev/null +++ b/src/main/java/org/jabref/gui/entryeditor/SciteTabViewModel.java @@ -0,0 +1,131 @@ +package org.jabref.gui.entryeditor; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Optional; +import java.util.concurrent.Future; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import org.jabref.gui.AbstractViewModel; +import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.importer.FetcherException; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.net.URLDownload; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.identifier.DOI; +import org.jabref.preferences.PreferencesService; + +import kong.unirest.json.JSONObject; +import org.tinylog.Logger; + +public class SciteTabViewModel extends AbstractViewModel { + + /** + * Status enum for Scite tab + */ + public enum SciteStatus { + IN_PROGRESS, + FOUND, + ERROR + } + + private static final String BASE_URL = "https://api.scite.ai/"; + private final PreferencesService preferencesService; + private final TaskExecutor taskExecutor; + private final ObjectProperty status; + private final StringProperty searchError; + private Optional currentResult = Optional.empty(); + + private Future searchTask; + + public SciteTabViewModel(PreferencesService preferencesService, TaskExecutor taskExecutor) { + this.preferencesService = preferencesService; + this.taskExecutor = taskExecutor; + this.status = new SimpleObjectProperty<>(SciteStatus.IN_PROGRESS); + this.searchError = new SimpleStringProperty(""); + } + + public boolean shouldShow() { + return preferencesService.getEntryEditorPreferences().shouldShowSciteTab(); + } + + public void bindToEntry(BibEntry entry) { + // If a search is already running, cancel it + cancelSearch(); + + if (entry == null) { + searchError.set(Localization.lang("No active entry")); + status.set(SciteStatus.ERROR); + return; + } + + // The scite.ai api requires a DOI + if (entry.getDOI().isEmpty()) { + searchError.set(Localization.lang("This entry does not have a DOI")); + status.set(SciteStatus.ERROR); + return; + } + + searchTask = BackgroundTask.wrap(() -> fetchTallies(entry.getDOI().get())) + .onRunning(() -> status.set(SciteStatus.IN_PROGRESS)) + .onSuccess(result -> { + currentResult = Optional.of(result); + status.set(SciteStatus.FOUND); + }) + .onFailure(error -> { + searchError.set(error.getMessage()); + status.set(SciteStatus.ERROR); + }) + .executeWith(taskExecutor); + } + + private void cancelSearch() { + if (searchTask == null || searchTask.isCancelled() || searchTask.isDone()) { + return; + } + + status.set(SciteStatus.IN_PROGRESS); + searchTask.cancel(true); + } + + public SciteTallyModel fetchTallies(DOI doi) throws FetcherException { + try { + URL url = new URI(BASE_URL + "tallies/" + doi.getDOI()).toURL(); + URLDownload download = new URLDownload(url); + String response = download.asString(); + Logger.debug("Response {}", response); + JSONObject tallies = new JSONObject(response); + if (tallies.has("detail")) { + String message = tallies.getString("detail"); + throw new FetcherException(message); + } else if (!tallies.has("total")) { + throw new FetcherException("Unexpected result data!"); + } + return SciteTallyModel.fromJSONObject(tallies); + } catch (MalformedURLException | URISyntaxException ex) { + throw new FetcherException("Malformed url for DOs", ex); + } catch (IOException ioex) { + throw new FetcherException("Failed to retrieve tallies for DOI - IO Exception", ioex); + } + } + + public ObjectProperty statusProperty() { + return status; + } + + public StringProperty searchErrorProperty() { + return searchError; + } + + public Optional getCurrentResult() { + return currentResult; + } +} diff --git a/src/main/java/org/jabref/gui/entryeditor/SciteTallyModel.java b/src/main/java/org/jabref/gui/entryeditor/SciteTallyModel.java new file mode 100644 index 00000000000..b3fbe24ea58 --- /dev/null +++ b/src/main/java/org/jabref/gui/entryeditor/SciteTallyModel.java @@ -0,0 +1,34 @@ +package org.jabref.gui.entryeditor; + +import kong.unirest.json.JSONObject; + +/** + * Simple model object to hold the scite.ai tallies data for a given DOI + */ +public record SciteTallyModel( + String doi, + int total, + int supporting, + int contradicting, + int mentioning, + int unclassified, + int citingPublications) { + + /** + * Creates a {@link SciteTallyModel} from a JSONObject (dictionary/map) + * + * @param jsonObject The JSON object holding the tally values + * @return a new {@link SciteTallyModel} + */ + public static SciteTallyModel fromJSONObject(JSONObject jsonObject) { + return new SciteTallyModel( + jsonObject.getString("doi"), + jsonObject.getInt("total"), + jsonObject.getInt("supporting"), + jsonObject.getInt("contradicting"), + jsonObject.getInt("mentioning"), + jsonObject.getInt("unclassified"), + jsonObject.getInt("citingPublications") + ); + } +} diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index 5148990b3be..5e817d5291c 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -65,6 +65,8 @@ public static FieldEditorFX getForField(final Field field, return new JournalEditor(field, suggestionProvider, fieldCheckers); } else if (fieldProperties.contains(FieldProperty.DOI) || fieldProperties.contains(FieldProperty.EPRINT) || fieldProperties.contains(FieldProperty.ISBN)) { return new IdentifierEditor(field, suggestionProvider, fieldCheckers); + } else if (fieldProperties.contains(FieldProperty.ISSN)) { + return new ISSNEditor(field, suggestionProvider, fieldCheckers); } else if (field == StandardField.OWNER) { return new OwnerEditor(field, suggestionProvider, fieldCheckers); } else if (field == StandardField.GROUPS) { @@ -97,8 +99,6 @@ public static FieldEditorFX getForField(final Field field, return new KeywordsEditor(field, suggestionProvider, fieldCheckers, preferences, undoManager); } else if (field == InternalField.KEY_FIELD) { return new CitationKeyEditor(field, suggestionProvider, fieldCheckers, databaseContext); - } else if (field == StandardField.ISSN) { - return new ISSNEditor(field, suggestionProvider, fieldCheckers); } else { // default return new SimpleEditor(field, suggestionProvider, fieldCheckers, preferences, isMultiLine, undoManager); diff --git a/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.fxml b/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.fxml index 021a0f24f60..44d70fb78c4 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.fxml +++ b/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.fxml @@ -3,13 +3,11 @@ - - + - - + diff --git a/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.java b/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.java index db100d37416..7fc01a07c4a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/ISSNEditor.java @@ -1,5 +1,7 @@ package org.jabref.gui.fieldeditors; +import java.util.Optional; + import javax.swing.undo.UndoManager; import javafx.fxml.FXML; @@ -8,6 +10,7 @@ import javafx.scene.layout.HBox; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.DefaultMenu; import org.jabref.gui.util.TaskExecutor; @@ -23,11 +26,14 @@ public class ISSNEditor extends HBox implements FieldEditorFX { @FXML private ISSNEditorViewModel viewModel; @FXML private EditorTextArea textArea; @FXML private Button journalInfoButton; + @FXML private Button fetchInformationByIdentifierButton; @Inject private DialogService dialogService; @Inject private PreferencesService preferencesService; @Inject private UndoManager undoManager; @Inject private TaskExecutor taskExecutor; + @Inject private StateManager stateManager; + private Optional entry = Optional.empty(); public ISSNEditor(Field field, SuggestionProvider suggestionProvider, @@ -43,7 +49,9 @@ public ISSNEditor(Field field, fieldCheckers, taskExecutor, dialogService, - undoManager); + undoManager, + stateManager, + preferencesService); textArea.textProperty().bindBidirectional(viewModel.textProperty()); textArea.initContextMenu(new DefaultMenu(textArea)); @@ -57,6 +65,7 @@ public ISSNEditorViewModel getViewModel() { @Override public void bindToEntry(BibEntry entry) { + this.entry = Optional.of(entry); viewModel.bindToEntry(entry); } @@ -70,6 +79,11 @@ public void requestFocus() { textArea.requestFocus(); } + @FXML + private void fetchInformationByIdentifier() { + entry.ifPresent(viewModel::fetchBibliographyInformation); + } + @FXML private void showJournalInfo() { if (JournalInfoOptInDialogHelper.isJournalInfoEnabled(dialogService, preferencesService.getEntryEditorPreferences())) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/ISSNEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/ISSNEditorViewModel.java index 4784580409d..89cbf76e949 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/ISSNEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/ISSNEditorViewModel.java @@ -5,14 +5,23 @@ import javafx.scene.control.Button; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.autocompleter.SuggestionProvider; +import org.jabref.gui.mergeentries.FetchAndMergeEntry; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.integrity.FieldCheckers; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.StandardField; +import org.jabref.preferences.PreferencesService; public class ISSNEditorViewModel extends AbstractEditorViewModel { private final TaskExecutor taskExecutor; private final DialogService dialogService; + private final UndoManager undoManager; + private final StateManager stateManager; + private final PreferencesService preferencesService; public ISSNEditorViewModel( Field field, @@ -20,13 +29,26 @@ public ISSNEditorViewModel( FieldCheckers fieldCheckers, TaskExecutor taskExecutor, DialogService dialogService, - UndoManager undoManager) { + UndoManager undoManager, + StateManager stateManager, + PreferencesService preferencesService) { super(field, suggestionProvider, fieldCheckers, undoManager); this.taskExecutor = taskExecutor; this.dialogService = dialogService; + this.undoManager = undoManager; + this.stateManager = stateManager; + this.preferencesService = preferencesService; } public void showJournalInfo(Button journalInfoButton) { PopOverUtil.showJournalInfo(journalInfoButton, entry, dialogService, taskExecutor); } + + public void fetchBibliographyInformation(BibEntry bibEntry) { + stateManager.getActiveDatabase().ifPresentOrElse( + databaseContext -> new FetchAndMergeEntry(databaseContext, taskExecutor, preferencesService, dialogService, undoManager) + .fetchAndMerge(bibEntry, StandardField.ISSN), + () -> dialogService.notify(Localization.lang("No library selected")) + ); + } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/JournalInfoOptInDialogHelper.java b/src/main/java/org/jabref/gui/fieldeditors/JournalInfoOptInDialogHelper.java index c811936a379..b1209ba95db 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/JournalInfoOptInDialogHelper.java +++ b/src/main/java/org/jabref/gui/fieldeditors/JournalInfoOptInDialogHelper.java @@ -15,12 +15,18 @@ public static boolean isJournalInfoEnabled(DialogService dialogService, EntryEdi } if (preferences.shouldEnableJournalPopup() == EntryEditorPreferences.JournalPopupEnabled.DISABLED) { - dialogService.notify( - Localization.lang("Please enable journal information fetching in %0 > %1", + boolean enableJournalPopup = dialogService.showConfirmationDialogAndWait( + Localization.lang("Enable Journal Information Fetching?"), + Localization.lang("Would you like to enable fetching of journal information? This can be changed later in %0 > %1.", Localization.lang("Preferences"), - Localization.lang("Web search")) + Localization.lang("Entry editor")), Localization.lang("Enable"), Localization.lang("Keep disabled") ); - return false; + + preferences.setEnableJournalPopup(enableJournalPopup + ? EntryEditorPreferences.JournalPopupEnabled.ENABLED + : EntryEditorPreferences.JournalPopupEnabled.DISABLED); + + return enableJournalPopup; } boolean journalInfoEnabled = dialogService.showConfirmationDialogAndWait( diff --git a/src/main/java/org/jabref/gui/fieldeditors/identifier/IdentifierEditor.java b/src/main/java/org/jabref/gui/fieldeditors/identifier/IdentifierEditor.java index c05501335b6..567f6c45047 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/identifier/IdentifierEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/identifier/IdentifierEditor.java @@ -23,13 +23,16 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.StandardField; import org.jabref.preferences.PreferencesService; import com.airhacks.afterburner.injection.Injector; import com.airhacks.afterburner.views.ViewLoader; import jakarta.inject.Inject; +import static org.jabref.model.entry.field.StandardField.DOI; +import static org.jabref.model.entry.field.StandardField.EPRINT; +import static org.jabref.model.entry.field.StandardField.ISBN; + public class IdentifierEditor extends HBox implements FieldEditorFX { @FXML private BaseIdentifierEditorViewModel viewModel; @@ -43,7 +46,7 @@ public class IdentifierEditor extends HBox implements FieldEditorFX { @Inject private UndoManager undoManager; @Inject private StateManager stateManager; - private Optional entry; + private Optional entry = Optional.empty(); public IdentifierEditor(Field field, SuggestionProvider suggestionProvider, @@ -53,14 +56,18 @@ public IdentifierEditor(Field field, // but we need the injected vars to create the viewmodels. Injector.registerExistingAndInject(this); - if (StandardField.DOI == field) { - this.viewModel = new DoiIdentifierEditorViewModel(suggestionProvider, fieldCheckers, dialogService, taskExecutor, preferencesService, undoManager, stateManager); - } else if (StandardField.ISBN == field) { - this.viewModel = new ISBNIdentifierEditorViewModel(suggestionProvider, fieldCheckers, dialogService, taskExecutor, preferencesService, undoManager, stateManager); - } else if (StandardField.EPRINT == field) { - this.viewModel = new EprintIdentifierEditorViewModel(suggestionProvider, fieldCheckers, dialogService, taskExecutor, preferencesService, undoManager); - } else { - throw new IllegalStateException(String.format("Unable to instantiate a view model for identifier field editor '%s'", field.getDisplayName())); + switch (field) { + case DOI -> + this.viewModel = new DoiIdentifierEditorViewModel(suggestionProvider, fieldCheckers, dialogService, taskExecutor, preferencesService, undoManager, stateManager); + case ISBN -> + this.viewModel = new ISBNIdentifierEditorViewModel(suggestionProvider, fieldCheckers, dialogService, taskExecutor, preferencesService, undoManager, stateManager); + case EPRINT -> + this.viewModel = new EprintIdentifierEditorViewModel(suggestionProvider, fieldCheckers, dialogService, taskExecutor, preferencesService, undoManager); + + case null, default -> { + assert field != null; + throw new IllegalStateException(String.format("Unable to instantiate a view model for identifier field editor '%s'", field.getDisplayName())); + } } ViewLoader.view(this) @@ -74,7 +81,7 @@ public IdentifierEditor(Field field, lookupIdentifierButton.setTooltip( new Tooltip(Localization.lang("Look up %0", field.getDisplayName()))); - if (field.equals(StandardField.DOI)) { + if (field.equals(DOI)) { textArea.initContextMenu(EditorMenus.getDOIMenu(textArea, dialogService, preferencesService)); } else { textArea.initContextMenu(new DefaultMenu(textArea)); diff --git a/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java b/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java index 5634e4e7450..985bede5b5a 100644 --- a/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java +++ b/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java @@ -1,7 +1,6 @@ package org.jabref.gui.importer.fetcher; import java.util.Map; -import java.util.SortedSet; import java.util.concurrent.Callable; import javafx.beans.property.ListProperty; @@ -57,10 +56,9 @@ public WebSearchPaneViewModel(PreferencesService preferencesService, DialogServi this.stateManager = stateManager; this.preferencesService = preferencesService; - SortedSet allFetchers = WebFetchers.getSearchBasedFetchers( + fetchers.setAll(WebFetchers.getSearchBasedFetchers( preferencesService.getImportFormatPreferences(), - preferencesService.getImporterPreferences()); - fetchers.setAll(allFetchers); + preferencesService.getImporterPreferences())); // Choose last-selected fetcher as default SidePanePreferences sidePanePreferences = preferencesService.getSidePanePreferences(); diff --git a/src/main/java/org/jabref/gui/preferences/entryeditor/EntryEditorTab.fxml b/src/main/java/org/jabref/gui/preferences/entryeditor/EntryEditorTab.fxml index 373d531eb8d..85b787fd4cb 100644 --- a/src/main/java/org/jabref/gui/preferences/entryeditor/EntryEditorTab.fxml +++ b/src/main/java/org/jabref/gui/preferences/entryeditor/EntryEditorTab.fxml @@ -34,6 +34,7 @@ +