diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index ddd732d0666..00000000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Configuration for https://dependabot.com -version: 1 - -update_configs: - - package_manager: "java:gradle" - directory: "/" - update_schedule: "weekly" - default_labels: - - "type: dependencies" - automerged_updates: - - match: - dependency_type: "all" - update_type: "semver:minor" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..226bf3a6f53 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: +- package-ecosystem: gradle + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 + labels: + - "type: dependencies" + ignore: + - dependency-name: com.microsoft.azure:applicationinsights-core + versions: + - ">= 2.5.a, <= 2.6.1" # Blocked by https://github.com/microsoft/ApplicationInsights-Java/issues/1155 + - dependency-name: com.microsoft.azure:applicationinsights-logging-log4j2 + versions: + - ">= 2.5.a, <= 2.6.1" # Blocked by https://github.com/microsoft/ApplicationInsights-Java/issues/1155 + - dependency-name: de.jensd:fontawesomefx-materialdesignfont + versions: + - "> 1.7.22-4" # Strange versioning format +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + labels: + - "type: dependencies" diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 00000000000..622fb41fb51 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,24 @@ +name: Automerge Pull Requests +on: [pull_request] + +jobs: + automerge: + name: Automerge Dependabot + runs-on: ubuntu-latest + if: github.actor == 'dependabot[bot]' + steps: + - name: 'Wait for status checks' + id: waitforstatuschecks + uses: "WyriHaximus/github-action-wait-for-status@0.1.0" + with: + ignoreActions: automerge + checkInterval: 13 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + - name: Merge pull requests + uses: pascalgn/automerge-action@v0.8.4 + if: steps.waitforstatuschecks.outputs.status == 'success' + env: + MERGE_METHOD: "squash" + MERGE_LABELS: "" + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/cleanup_pr.yml b/.github/workflows/cleanup_pr.yml index b43abfb5678..5131865fc97 100644 --- a/.github/workflows/cleanup_pr.yml +++ b/.github/workflows/cleanup_pr.yml @@ -27,7 +27,7 @@ jobs: echo "##[set-output name=branch;]$(echo ${{ github.event.pull_request.head.ref }})" - name: Delete folder on builds.jabref.org if: ${{ steps.checksecrets.outputs.secretspresent }} - uses: appleboy/ssh-action@v0.0.6 + uses: appleboy/ssh-action@v0.1.2 with: script: rm -rf /var/www/builds.jabref.org/www/${{ steps.extract_branch.outputs.branch }} || true host: build-upload.jabref.org diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 63baf4960d9..ecd2f9d3158 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -17,6 +17,8 @@ on: env: SpringerNatureAPIKey: ${{ secrets.SpringerNatureAPIKey }} + AstrophysicsDataSystemAPIKey: ${{ secrets.AstrophysicsDataSystemAPIKey }} + IEEEAPIKey: ${{ secrets.IEEEAPIKey }} jobs: build: @@ -44,12 +46,12 @@ jobs: - name: Fetch all history for all tags and branches run: git fetch --prune --unshallow - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v0.9.2 + uses: gittools/actions/gitversion/setup@v0.9.3 with: versionSpec: '5.2.x' - name: Run GitVersion id: gitversion - uses: gittools/actions/gitversion/execute@v0.9.2 + uses: gittools/actions/gitversion/execute@v0.9.3 - name: Set up JDK uses: actions/setup-java@v1 with: @@ -101,12 +103,12 @@ jobs: - name: Fetch all history for all tags and branches run: git fetch --prune --unshallow - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v0.9.2 + uses: gittools/actions/gitversion/setup@v0.9.3 with: versionSpec: '5.2.x' - name: Run GitVersion id: gitversion - uses: gittools/actions/gitversion/execute@v0.9.2 + uses: gittools/actions/gitversion/execute@v0.9.3 - name: Get linux binaries uses: actions/download-artifact@master with: diff --git a/.github/workflows/tests-fetchers.yml b/.github/workflows/tests-fetchers.yml index 72b6533bd8d..9d30f9c7864 100644 --- a/.github/workflows/tests-fetchers.yml +++ b/.github/workflows/tests-fetchers.yml @@ -23,6 +23,8 @@ on: env: SpringerNatureAPIKey: ${{ secrets.SpringerNatureAPIKey }} + AstrophysicsDataSystemAPIKey: ${{ secrets.AstrophysicsDataSystemAPIKey }} + IEEEAPIKey: ${{ secrets.IEEEAPIKey }} jobs: fetchertests: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 572c836fe90..1262b90b6da 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,6 +9,8 @@ on: env: SpringerNatureAPIKey: ${{ secrets.SpringerNatureAPIKey }} + AstrophysicsDataSystemAPIKey: ${{ secrets.AstrophysicsDataSystemAPIKey }} + IEEEAPIKey: ${{ secrets.IEEEAPIKey }} jobs: checkstyle: @@ -37,6 +39,20 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - name: Run checkstyle run: ./gradlew checkstyleMain checkstyleTest checkstyleJmh + - name: Run markdown-lint + uses: avto-dev/markdown-lint@v1 + with: + args: CHANGELOG.md CONTRIBUTING.md README.md docs/ + config: '.markdownlint.yml' + - name: Prepare markdown-link-check + run: mkdir docs/ROOT && cp CHANGELOG.md README.md docs/ROOT + - name: Run markdown-link-check + 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/' tests: name: Unit tests runs-on: ubuntu-latest diff --git a/.mailmap b/.mailmap index cb4da018a86..f2fdffb10b9 100644 --- a/.mailmap +++ b/.mailmap @@ -200,3 +200,5 @@ Gennadiy Stakhovskiy Mootez Saad <34676841+MootezSaaD@users.noreply.github.com> Mootez Saad <34676841+MootezSaaD@users.noreply.github.com> Chen Yuheng +Dominik Voigt <43381984+DominikVoigt@users.noreply.github.com> +Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 00000000000..84a9c96a53a --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,18 @@ +default: true + +# Using h2 has side effects in GitBook's toc. Thus, we sometimes switch from h1 to h3 +MD001: false + +MD012: + # 2 are required, because GitBook adss two blank lines at the end of a file + maximum: 2 + +MD013: false + +# The FAQs state questions - we allow them +MD026: + punctuation: ".,;:!" + +MD033: + # we have tags with ids + allowed_elements: ['a'] diff --git a/AUTHORS b/AUTHORS index 40b6b524e3f..7795b1f4c78 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,6 +29,7 @@ Andreas Buhr Andreas Rudert Andrew Collins Andrew Levit +André Schlichting Andrés Sánchez Anh Nghia Tran Anita Armbruster @@ -40,6 +41,7 @@ August Janse Ayachi Nene Bartosz J. Kaczkowski Bartłomiej Dach +Baruch Oltman Behrouz Javanmardi Benedikt Tutzer Benjamin Köhler @@ -96,6 +98,7 @@ Dimitra Karadima Domenico Cufalo Dominik Schrempf Dominik Traczyk +Dominik Voigt Dominik Waßenhoven Douglas Nassif Roma Junior Eduard Braun @@ -260,6 +263,7 @@ Nick S. Weatherley Nico Schlömer Nicolas Pavillon Nikita Borovikov +Niklas Schmitt nikmilpv NikodemKch Niv Ierushalmi diff --git a/CHANGELOG.md b/CHANGELOG.md index e443c7ae84d..55fc8d8410e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve ## [Unreleased] ### 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 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. [#6643](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) - We added the Library properties to a context menu on the library tabs [#6485](https://github.com/JabRef/jabref/issues/6485) - We added a new field in the preferences in 'BibTeX key generator' for unwanted characters that can be user-specified. [#6295](https://github.com/JabRef/jabref/issues/6295) - We added support for searching ShortScience for an entry through the user's browser. [#6018](https://github.com/JabRef/jabref/pull/6018) @@ -24,6 +30,9 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed the bug when strike the delete key in the text field. [#6421](https://github.com/JabRef/jabref/issues/6421) - We added a BibTex key modifier for truncating strings. [#3915](https://github.com/JabRef/jabref/issues/3915) - We added support for jumping to target entry when typing letter/digit after sorting a column in maintable [#6146](https://github.com/JabRef/jabref/issues/6146) +- We added a new fetcher to enable users to search all available E-Libraries simultaneously. [koppor#369](https://github.com/koppor/jabref/issues/369) +- We added the field "entrytype" to the export sort criteria [#6531](https://github.com/JabRef/jabref/pull/6531) +- We added the possibility to change the display order of the fields in the entry editor. The order can now be configured using drag and drop in the "Customize entry types" dialog [#6152](https://github.com/JabRef/jabref/pull/6152) ### Changed @@ -37,9 +46,14 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We improved the error message for invalid jstyles. [#6303](https://github.com/JabRef/jabref/issues/6303) - We changed the section name of 'Advanced' to 'Network' in the preferences and removed some obsolete options.[#6489](https://github.com/JabRef/jabref/pull/6489) - We improved the context menu of the column "Linked identifiers" of the main table, by truncating their texts, if they are too long. [#6499](https://github.com/JabRef/jabref/issues/6499) +- We merged the main table tabs in the preferences dialog. [#6518](https://github.com/JabRef/jabref/pull/6518) +- We changed the command line option 'generateBibtexKeys' to the more generic term 'generateCitationKeys' while the short option remains 'g'.[#6545](https://github.com/JabRef/jabref/pull/6545) +- We improved the "Possible duplicate entries" window to remember its size and position throughout a session. [#6582](https://github.com/JabRef/jabref/issues/6582) ### Fixed +- We fixed an issue where entry preview tab has no name in drop down list. [#6591](https://github.com/JabRef/jabref/issues/6591) +- We fixed to only search file links in the BIB file location directory when preferences has corresponding checkbox checked. [#5891](https://github.com/JabRef/jabref/issues/5891) - We fixed wrong button order (Apply and Cancel) in ManageProtectedTermsDialog. - We fixed an issue with incompatible characters at BibTeX key [#6257](https://github.com/JabRef/jabref/issues/6257) - We fixed an issue where dash (`-`) was reported as illegal BibTeX key [#6295](https://github.com/JabRef/jabref/issues/6295) @@ -70,8 +84,17 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where an "Not on FX thread" exception occured when saving on linux [#6453](https://github.com/JabRef/jabref/issues/6453) - We fixed an issue where the library sort order was lost. [#6091](https://github.com/JabRef/jabref/issues/6091) - We fixed an issue where brackets in regular expressions were not working. [6469](https://github.com/JabRef/jabref/pull/6469) +- We fixed an issue where multiple background task popups stacked over each other.. [#6472](https://github.com/JabRef/jabref/issues/6472) - We fixed an issue where LaTeX citations for specific commands (\autocites) of biblatex-mla were not recognized. [#6476](https://github.com/JabRef/jabref/issues/6476) - We fixed an issue where drag and drop was not working on empty database. [#6487](https://github.com/JabRef/jabref/issues/6487) +- We fixed an issue where the name fields were not updated after the preferences changed. [#6515](https://github.com/JabRef/jabref/issues/6515) +- We fixed an issue where "null" appeared in generated BibTeX keys. [#6459](https://github.com/JabRef/jabref/issues/6459) +- We fixed an issue where the authors' names were incorrectly displayed in the authors' column when they were bracketed. [#6465](https://github.com/JabRef/jabref/issues/6465) [#6459](https://github.com/JabRef/jabref/issues/6459) +- We fixed an issue where importing certain unlinked files would result in an exception [#5815](https://github.com/JabRef/jabref/issues/5815) +- We fixed an issue where downloaded files would be moved to a directory named after the citationkey when no file directory pattern is specified [#6589](https://github.com/JabRef/jabref/issues/6589) +- We fixed an issue with the creation of a group of cited entries which incorrectly showed the message that the library had been modified externally whenever saving the library. [#6420](https://github.com/JabRef/jabref/issues/6420) +- We fixed an issue with the creation of a group of cited entries. Now the file path to an aux file gets validated. [#6585](https://github.com/JabRef/jabref/issues/6585) +- We fixed an issue on Linux systems where the application would crash upon inotify failure. Now, the user is prompted with a warning, and given the choice to continue the session. [#6073](https://github.com/JabRef/jabref/issues/6073) ### Removed @@ -128,6 +151,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where the blue and red text colors in the Merge entries dialog were not quite visible [#6334](https://github.com/JabRef/jabref/issues/6334) - We fixed an issue where underscore character was removed from the file name in the Recent Libraries list in File menu [#6383](https://github.com/JabRef/jabref/issues/6383) - We fixed an issue where few keyboard shortcuts regarding new entries were missing [#6403](https://github.com/JabRef/jabref/issues/6403) + ### Removed - Ampersands are no longer escaped by default in the `bib` file. If you want to keep the current behaviour, you can use the new "Escape Ampersands" formatter as a save action. [#5869](https://github.com/JabRef/jabref/issues/5869) @@ -303,8 +327,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where some journal names were wrongly marked as abbreviated. [#4115](https://github.com/JabRef/jabref/issues/4115) - We fixed an issue where the custom file column were sorted incorrectly. [#3119](https://github.com/JabRef/jabref/issues/3119) - We improved the parsing of author names whose infix is abbreviated without a dot. [#4864](https://github.com/JabRef/jabref/issues/4864) -- We fixed an issues where the entry losses focus when a field is edited and at the same time used for sorting. https://github.com/JabRef/jabref/issues/3373 -- We fixed an issue where the menu on Mac OS was not displayed in the usual Mac-specific way. https://github.com/JabRef/jabref/issues/3146 +- We fixed an issues where the entry losses focus when a field is edited and at the same time used for sorting. [#3373](https://github.com/JabRef/jabref/issues/3373) +- We fixed an issue where the menu on Mac OS was not displayed in the usual Mac-specific way. [#3146](https://github.com/JabRef/jabref/issues/3146) - We improved the integrity check for page numbers. [#4113](https://github.com/JabRef/jabref/issues/4113) and [feature request in the forum](http://discourse.jabref.org/t/pages-field-allow-use-of-en-dash/1199) - We fixed an issue where the order of fields in customized entry types was not saved correctly. [#4033](http://github.com/JabRef/jabref/issues/4033) - We fixed an issue where renaming a group did not change the group name in the interface. [#3189](https://github.com/JabRef/jabref/issues/3189) @@ -341,6 +365,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where the "Attach file" dialog, in the right-click menu for an entry, started on the working directory instead of the user's main directory. [#4995](https://github.com/JabRef/jabref/issues/4995) - We fixed an issue where the JabRef Icon in the macOS launchpad was not displayed correctly [#5003](https://github.com/JabRef/jabref/issues/5003) - We fixed an issue where the "Search for unlinked local files" would throw an exception when parsing the content of a PDF-file with missing "series" information [#5128](https://github.com/JabRef/jabref/issues/5128) +- We fixed an issue where the XMP Importer would incorrectly return an empty default entry when importing pdfs [#6577](https://github.com/JabRef/jabref/issues/6577) +- We fixed an issue where opening the menu 'Library properties' marked the library as modified [#6451](https://github.com/JabRef/jabref/issues/6451) ### Removed diff --git a/README.md b/README.md index da480916196..d81ab2b909e 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,12 @@ JabRef is an open-source, cross-platform citation and reference management tool. Stay on top of your literature: JabRef helps you to collect and organize sources, find the paper you need and discover the latest research. -![main table](https://www.jabref.org/img/jabref-5-0-maintable.png) +![main table](http://www.jabref.org/img/jabref-mainscreen.png) ## Features -JabRef is a cross-platform application that works on Windows, Linux and Mac OS X. It is available free of charge and is actively developed. -JabRef supports you in every step of your research work. +JabRef is available free of charge and is actively developed. +It supports you in every step of your research work. ### Collect @@ -33,7 +33,7 @@ JabRef supports you in every step of your research work. ### Cite -- Native [BibTeX] and [Biblatex] support +- Native BibTeX and Biblatex support - Cite-as-you-write functionality for external applications such as Emacs, Kile, LyX, Texmaker, TeXstudio, Vim and WinEdt. - Format references in one of the many thousand built-in citation styles or create your style - Support for Word and LibreOffice/OpenOffice for inserting and formatting citations @@ -47,11 +47,9 @@ JabRef supports you in every step of your research work. ## Installation Fresh development builds are available at [builds.jabref.org](https://builds.jabref.org/master/). -The [latest stable release is available at FossHub](https://www.fosshub.com/JabRef.html). +The [latest stable release is available at FossHub](https://downloads.jabref.org/). -- Windows: JabRef offers an installer, which also adds a shortcut to JabRef to your start menu. Please also see our [Windows FAQ](https://docs.jabref.org/faq/faqwindows) -- Linux: Please see our [Installation Guide](https://docs.jabref.org/general/installation). -- Mac OS X: Please see our [Mac OS X FAQ](https://docs.jabref.org/faq/faqosx). +Please see our [Installation Guide](https://docs.jabref.org/installation). ## Bug Reports, Suggestions, Other Feedback @@ -98,8 +96,4 @@ For IntelliJ IDEA, just import the project via a Gradle Import by pointing at th `gradlew test` executes all tests. We use [Github Actions](https://github.com/JabRef/jabref/actions) for executing the tests after each commit. For developing, it is sufficient to locally only run the associated test for the classes you changed. Github will report any other failure. -[BibTeX]: https://www.ctan.org/pkg/bibtex -[Biblatex]: https://www.ctan.org/pkg/biblatex -[install4j]: https://www.ej-technologies.com/products/install4j/overview.html [JabRef]: https://www.jabref.org -[JavaFX]: https://en.wikipedia.org/wiki/JavaFX diff --git a/build.gradle b/build.gradle index 21ea43e1a99..5d07041cf1e 100644 --- a/build.gradle +++ b/build.gradle @@ -11,15 +11,15 @@ import org.jabref.build.xjc.XjcTask plugins { id 'application' - id "com.simonharrer.modernizer" version '1.8.0-1' + id "com.simonharrer.modernizer" version '2.1.0-1' id 'me.champeau.gradle.jmh' version '0.5.0' id 'com.github.ben-manes.versions' version '0.28.0' - id 'org.javamodularity.moduleplugin' version '1.5.0' - id 'org.openjfx.javafxplugin' version '0.0.8' - id 'org.beryx.jlink' version '2.19.0' + id 'org.javamodularity.moduleplugin' version '1.7.0' + id 'org.openjfx.javafxplugin' version '0.0.9' + id 'org.beryx.jlink' version '2.21.0' // nicer test outputs during running and completion - id 'com.adarshr.test-logger' version '2.0.0' + id 'com.adarshr.test-logger' version '2.1.0' } gradle.startParameter.showStacktrace = org.gradle.api.logging.configuration.ShowStacktrace.ALWAYS @@ -50,11 +50,9 @@ application { // TODO: Ugly workaround to temporarily ignore build errors to dependencies of latex2unicode // These should be removed, as well as the files in the lib folder, as soon as they have valid module names -patchModules.config = [ - "test=fastparse_2.12-1.0.0.jar", - "test2=fastparse-utils_2.12-1.0.0.jar", - "test3=sourcecode_2.12-0.1.4.jar" -] +modularity.patchModule("test", "fastparse_2.12-1.0.0.jar") +modularity.patchModule("test2", "fastparse-utils_2.12-1.0.0.jar") +modularity.patchModule("test3", "sourcecode_2.12-0.1.4.jar") // These are the Java version requirements we will check on each start of JabRef ext.minRequiredJavaVersion = "1.8.0_171" @@ -106,9 +104,9 @@ dependencies { // Include all jar-files in the 'lib' folder as dependencies implementation fileTree(dir: 'lib', includes: ['*.jar']) - implementation 'org.apache.pdfbox:pdfbox:2.0.19' - implementation 'org.apache.pdfbox:fontbox:2.0.19' - implementation 'org.apache.pdfbox:xmpbox:2.0.19' + implementation 'org.apache.pdfbox:pdfbox:2.0.20' + implementation 'org.apache.pdfbox:fontbox:2.0.20' + implementation 'org.apache.pdfbox:xmpbox:2.0.20' implementation group: 'org.apache.commons', name: 'commons-csv', version: '1.8' implementation 'com.h2database:h2-mvstore:1.4.200' @@ -116,7 +114,7 @@ dependencies { implementation group: 'org.apache.tika', name: 'tika-core', version: '1.24.1' // required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635 - implementation 'org.bouncycastle:bcprov-jdk15on:1.65' + implementation 'org.bouncycastle:bcprov-jdk15on:1.66' implementation 'commons-cli:commons-cli:1.4' @@ -138,9 +136,9 @@ dependencies { antlr4 'org.antlr:antlr4:4.8-1' implementation 'org.antlr:antlr4-runtime:4.8-1' - implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.6.0' + implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.6.1' - implementation 'org.postgresql:postgresql:42.2.12' + implementation 'org.postgresql:postgresql:42.2.14' implementation ('com.oracle.ojdbc:ojdbc10:19.3.0.0') { // causing module issues @@ -163,11 +161,11 @@ dependencies { implementation 'org.fxmisc.flowless:flowless:0.6.1' implementation 'org.fxmisc.richtext:richtextfx:0.10.5' implementation group: 'org.glassfish.hk2.external', name: 'jakarta.inject', version: '2.6.1' - implementation 'com.jfoenix:jfoenix:9.0.9' - implementation 'org.controlsfx:controlsfx:11.0.1' + implementation 'com.jfoenix:jfoenix:9.0.10' + implementation 'org.controlsfx:controlsfx:11.0.2' implementation 'org.jsoup:jsoup:1.13.1' - implementation 'com.konghq:unirest-java:3.7.02' + implementation 'com.konghq:unirest-java:3.8.06' implementation 'org.slf4j:slf4j-api:2.0.0-alpha1' implementation group: 'org.apache.logging.log4j', name: 'log4j-jcl', version: '3.0.0-SNAPSHOT' @@ -192,16 +190,16 @@ dependencies { exclude module: "log4j-core" } - implementation 'com.vladsch.flexmark:flexmark:0.61.32' - implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.61.32' - implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.61.32' + implementation 'com.vladsch.flexmark:flexmark:0.62.2' + implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.62.2' + implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.62.2' - testImplementation 'io.github.classgraph:classgraph:4.8.78' + testImplementation 'io.github.classgraph:classgraph:4.8.87' testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.6.2' testImplementation 'org.junit.platform:junit-platform-launcher:1.6.2' - testImplementation 'net.bytebuddy:byte-buddy-parent:1.10.10' + testImplementation 'net.bytebuddy:byte-buddy-parent:1.10.13' testRuntime group: 'org.apache.logging.log4j', name: 'log4j-core', version: '3.0.0-SNAPSHOT' testRuntime group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '3.0.0-SNAPSHOT' testImplementation 'org.mockito:mockito-core:3.3.3' @@ -212,7 +210,7 @@ dependencies { testImplementation "org.testfx:testfx-junit5:4.0.17-alpha-SNAPSHOT" testImplementation "org.hamcrest:hamcrest-library:2.2" - checkstyle 'com.puppycrawl.tools:checkstyle:8.32' + checkstyle 'com.puppycrawl.tools:checkstyle:8.34' xjc group: 'org.glassfish.jaxb', name: 'jaxb-xjc', version: '2.3.3' jython 'org.python:jython-standalone:2.7.2' } @@ -276,6 +274,8 @@ processResources { "developers": new File('DEVELOPERS').readLines().findAll { !it.startsWith("#") }.join(", "), "azureInstrumentationKey": System.getenv('AzureInstrumentationKey'), "springerNatureAPIKey": System.getenv('SpringerNatureAPIKey'), + "astrophysicsDataSystemAPIKey": System.getenv('AstrophysicsDataSystemAPIKey'), + "ieeeAPIKey": System.getenv('IEEEAPIKey'), "minRequiredJavaVersion": minRequiredJavaVersion, "allowJava9": allowJava9 @@ -383,45 +383,41 @@ compileJava { run { // TODO: Remove access to internal api - jvmArgs '--add-exports', 'javafx.controls/com.sun.javafx.scene.control=org.jabref', - '--add-exports', 'org.controlsfx.controls/impl.org.controlsfx.skin=org.jabref', - '--add-opens', 'javafx.controls/javafx.scene.control=org.jabref', - '--add-opens', 'org.controlsfx.controls/org.controlsfx.control.textfield=org.jabref', - '--add-opens', 'javafx.controls/com.sun.javafx.scene.control=org.jabref', - // Not sure why we need to restate the controlfx exports - // Taken from here: https://github.com/controlsfx/controlsfx/blob/9.0.0/build.gradle#L1 - "--add-exports", "javafx.graphics/com.sun.javafx.scene=org.controlsfx.controls", - "--add-exports", "javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls", - "--add-exports", "javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", - "--add-exports", "javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls", - "--add-exports", "javafx.controls/com.sun.javafx.scene.control=org.controlsfx.controls", - "--add-exports", "javafx.controls/com.sun.javafx.scene.control.inputmap=org.controlsfx.controls", - "--add-exports", "javafx.base/com.sun.javafx.event=org.controlsfx.controls", - "--add-exports", "javafx.base/com.sun.javafx.collections=org.controlsfx.controls", - "--add-exports", "javafx.base/com.sun.javafx.runtime=org.controlsfx.controls", - "--add-exports", "javafx.web/com.sun.webkit=org.controlsfx.controls", - "--add-exports", "javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", - "--add-opens", "javafx.controls/javafx.scene.control.skin=org.controlsfx.controls", - "--add-opens", "javafx.graphics/javafx.scene=org.controlsfx.controls", - "--add-exports", "javafx.controls/com.sun.javafx.scene.control.behavior=com.jfoenix", - "--add-opens", "javafx.controls/com.sun.javafx.scene.control.behavior=com.jfoenix", - "--add-opens", "javafx.base/com.sun.javafx.binding=com.jfoenix", - "--add-opens", "javafx.graphics/com.sun.javafx.stage=com.jfoenix", - "--add-opens", "javafx.base/com.sun.javafx.event=com.jfoenix", - '--add-exports', 'com.oracle.truffle.regex/com.oracle.truffle.regex=org.graalvm.truffle' - - // TODO: The following code should have the same affect as the above one, but doesn't work for some reason - // https://github.com/java9-modularity/gradle-modules-plugin/issues/89 moduleOptions { addExports = [ 'javafx.controls/com.sun.javafx.scene.control' : 'org.jabref', 'org.controlsfx.controls/impl.org.controlsfx.skin' : 'org.jabref', - 'com.oracle.truffle.regex/com.oracle.truffle.regex' : 'org.graalvm.truffle' + + 'javafx.controls/com.sun.javafx.scene.control.behavior' : 'com.jfoenix', + 'com.oracle.truffle.regex/com.oracle.truffle.regex' : 'org.graalvm.truffle', + + // Not sure why we need to restate the controlfx exports + // Taken from here: https://github.com/controlsfx/controlsfx/blob/9.0.0/build.gradle#L1 + 'javafx.graphics/com.sun.javafx.scene' : 'org.controlsfx.controls', + 'javafx.graphics/com.sun.javafx.scene.traversal' : 'org.controlsfx.controls', + 'javafx.graphics/com.sun.javafx.css' : 'org.controlsfx.controls', + 'javafx.controls/com.sun.javafx.scene.control.behavior' : 'org.controlsfx.controls', + 'javafx.controls/com.sun.javafx.scene.control' : 'org.controlsfx.controls', + 'javafx.controls/com.sun.javafx.scene.control.inputmap' : 'org.controlsfx.controls', + 'javafx.base/com.sun.javafx.event' : 'org.controlsfx.controls', + 'javafx.base/com.sun.javafx.collections' : 'org.controlsfx.controls', + 'javafx.base/com.sun.javafx.runtime': 'org.controlsfx.controls', + 'javafx.web/com.sun.webkit' : 'org.controlsfx.controls', + 'javafx.graphics/com.sun.javafx.css' : 'org.controlsfx.controls' ] addOpens = [ 'javafx.controls/javafx.scene.control' : 'org.jabref', - 'org.controlsfx.controls/org.controlsfx.control.textfield' : 'org.jabref' + 'org.controlsfx.controls/org.controlsfx.control.textfield' : 'org.jabref', + 'javafx.controls/com.sun.javafx.scene.control' : 'org.jabref', + + 'javafx.controls/javafx.scene.control.skin' : 'org.controlsfx.controls', + 'javafx.graphics/javafx.scene' : 'org.controlsfx.controls', + + 'javafx.controls/com.sun.javafx.scene.control.behavior' : 'com.jfoenix', + 'javafx.base/com.sun.javafx.binding' : 'com.jfoenix', + 'javafx.graphics/com.sun.javafx.stage' : 'com.jfoenix', + 'javafx.base/com.sun.javafx.event' : 'com.jfoenix' ] } } @@ -573,7 +569,6 @@ jlink { requires 'java.management' requires 'java.naming' requires 'java.security.sasl' - requires 'com.sun.xml.fastinfoset' requires 'jdk.security.jgss' requires 'java.logging' requires 'jdk.xml.dom' diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index ade463b0d6c..2b267604f65 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -12,7 +12,7 @@ - + diff --git a/docs/.gitbook/assets/contribution-process-reviews-with-instructor.svg b/docs/.gitbook/assets/contribution-process-reviews-with-instructor.svg new file mode 100644 index 00000000000..7e196fe5e1a --- /dev/null +++ b/docs/.gitbook/assets/contribution-process-reviews-with-instructor.svg @@ -0,0 +1,4 @@ + + + +ContributorPrepare SubmissionSubmit and Refine ContributionJabRef TeamCheck, Support,and MergeInstructorReview and Support Submission \ No newline at end of file diff --git a/docs/.gitbook/assets/contribution-process-reviews.svg b/docs/.gitbook/assets/contribution-process-reviews.svg new file mode 100644 index 00000000000..39951a21137 --- /dev/null +++ b/docs/.gitbook/assets/contribution-process-reviews.svg @@ -0,0 +1,4 @@ + + + +ContributorCreate ContributionSubmit ContributionUpdate CodeComment Pull RequestJabRef TeamFrist DeveloperSecond DeveloperProvide FeedbackReview CodeProvide FeedbackReview CodeRequest ChangesMerge Pull ReuquestQuality OKQuality does not meet JabRef's requirementsQuality does not meet JabRef's requirementsPull Request incomingQuality OK`?Quality OK?Quality OKEverything OKChanges Requested \ No newline at end of file diff --git a/docs/.gitbook/assets/github-flow.png b/docs/.gitbook/assets/github-flow.png new file mode 100644 index 00000000000..dc9fdeb82bc Binary files /dev/null and b/docs/.gitbook/assets/github-flow.png differ diff --git a/docs/.gitbook/assets/grafik.png b/docs/.gitbook/assets/grafik.png new file mode 100644 index 00000000000..c3b7615fdda Binary files /dev/null and b/docs/.gitbook/assets/grafik.png differ diff --git a/docs/.gitbook/assets/intellij-checkstyle-settings.png b/docs/.gitbook/assets/intellij-checkstyle-settings.png new file mode 100644 index 00000000000..e5f0c027190 Binary files /dev/null and b/docs/.gitbook/assets/intellij-checkstyle-settings.png differ diff --git a/docs/.gitbook/assets/intellij-gradle-config (1).png b/docs/.gitbook/assets/intellij-gradle-config (1).png new file mode 100644 index 00000000000..deb452c88b8 Binary files /dev/null and b/docs/.gitbook/assets/intellij-gradle-config (1).png differ diff --git a/docs/.gitbook/assets/intellij-gradle-config-ignore-buildSrc.png b/docs/.gitbook/assets/intellij-gradle-config-ignore-buildSrc.png new file mode 100644 index 00000000000..203ad5ad207 Binary files /dev/null and b/docs/.gitbook/assets/intellij-gradle-config-ignore-buildSrc.png differ diff --git a/docs/.gitbook/assets/intellij-gradle-config.png b/docs/.gitbook/assets/intellij-gradle-config.png new file mode 100644 index 00000000000..deb452c88b8 Binary files /dev/null and b/docs/.gitbook/assets/intellij-gradle-config.png differ diff --git a/docs/.gitbook/assets/intellij-run-configuration-command-line (1).png b/docs/.gitbook/assets/intellij-run-configuration-command-line (1).png new file mode 100644 index 00000000000..cc71d5d068e Binary files /dev/null and b/docs/.gitbook/assets/intellij-run-configuration-command-line (1).png differ diff --git a/docs/.gitbook/assets/intellij-run-configuration-command-line (2).png b/docs/.gitbook/assets/intellij-run-configuration-command-line (2).png new file mode 100644 index 00000000000..cc71d5d068e Binary files /dev/null and b/docs/.gitbook/assets/intellij-run-configuration-command-line (2).png differ diff --git a/docs/.gitbook/assets/intellij-run-configuration-command-line.png b/docs/.gitbook/assets/intellij-run-configuration-command-line.png new file mode 100644 index 00000000000..cc71d5d068e Binary files /dev/null and b/docs/.gitbook/assets/intellij-run-configuration-command-line.png differ diff --git a/docs/README.md b/docs/README.md index 4287ad7e8d9..6fdbda908c2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,48 +1,65 @@ -# Develop JabRef +# Overview on Developing -This page presents all development informatation around JabRef. For users documentation see [https://docs.jabref.org](https://docs.jabref.org). +This page presents all development informatation around JabRef. -## Teaching Exercises +## Starting point for newcomers + +Go to [Setting up a local workspace](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace) + +## User documentation -We are very happy that JabRef is part of [Software Engineering](https://en.wikipedia.org/wiki/Software_engineering) trainings. -Please head to [Teaching](teaching.md) for more information on using JabRef as teaching object and on previous courses where JabRef was used. +For users documentation, please head to [https://docs.jabref.org](https://docs.jabref.org). ## How tos * External: [Sync your fork with the JabRef repository](https://help.github.com/articles/syncing-a-fork/) * External \(🇩🇪\): Branches and pull requests: [https://github.com/unibas-marcelluethi/software-engineering/blob/master/docs/week2/exercises/practical-exercises.md](https://github.com/unibas-marcelluethi/software-engineering/blob/master/docs/week2/exercises/practical-exercises.md) -## Command Line +## Teaching Exercises + +We are very happy that JabRef is part of [Software Engineering](https://en.wikipedia.org/wiki/Software_engineering) trainings. Please head to [Teaching](teaching.md) for more information on using JabRef as teaching object and on previous courses where JabRef was used. + +## Miscellaneous Hints + +### Command Line The package `org.jabref.cli` is responsible for handling the command line options. During development, one can configure IntelliJ to pass command line paramters: -![IntelliJ-run-configuration](images/intellij-run-configuration-command-line.png) +![IntelliJ-run-configuration](.gitbook/assets/intellij-run-configuration-command-line%20%282%29.png) Passing command line arguments using gradle is currently not possible as all arguments \(such as `-Dfile.encoding=windows-1252`\) are passed to the application. Without jlink, it is not possible to generate a fat jar any more. During development, the capabilities of the IDE has to be used. -## Groups +### Groups -Diagram showing aspects of groups: [Groups.uml](Groups.uml). +Diagram showing aspects of groups: [Groups.uml](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/Groups.uml). ## Decision Records This log lists the decisions for JabRef. -* [ADR-0000](adr/0000-use-markdown-architectural-decision-records.md) - Use Markdown Architectural Decision Records -* [ADR-0001](adr/0001-use-crowdin-for-translations.md) - Use Crowdin for translations -* [ADR-0002](adr/0002-use-slf4j-for-logging.md) - Use slf4j together with log4j2 for logging -* [ADR-0003](adr/0003-use-gradle-as-build-tool.md) - Use Gradle as build tool -* [ADR-0004](adr/0004-use-mariadb-connector.md) - Use MariaDB Connector -* [ADR-0005](adr/0005-fully-support-utf8-only-for-latex-files.md) - Fully Support UTF-8 Only For LaTeX Files -* [ADR-0006](adr/0006-only-translated-strings-in-language-file.md) - Only translated strings in language file -* [ADR-0007](adr/0007-human-readable-changelog.md) - Provide a human-readable changelog -* [ADR-0008](adr/0008-use-public-final-instead-of-getters.md) - Use public final instead of getters to offer access to immutable variables -* [ADR-0009](adr/0009-use-plain-junit5-for-testing.md) - Use Plain JUnit5 for advanced test assertions -* [ADR-0010](0010-use-h2-as-internal-database.md) - Use H2 as Internal SQL Database - -For new ADRs, please use [template.md](adr/template.md) as basis. More information on MADR is available at [https://adr.github.io/madr/](https://adr.github.io/madr/). General information about architectural decision records is available at [https://adr.github.io/](https://adr.github.io/). +* [ADR-0000](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0000-use-markdown-architectural-decision-records.md) - Use Markdown Architectural Decision Records +* [ADR-0001](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0001-use-crowdin-for-translations.md) - Use Crowdin for translations +* [ADR-0002](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0002-use-slf4j-for-logging.md) - Use slf4j together with log4j2 for logging +* [ADR-0003](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0003-use-gradle-as-build-tool.md) - Use Gradle as build tool +* [ADR-0004](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0004-use-mariadb-connector.md) - Use MariaDB Connector +* [ADR-0005](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0005-fully-support-utf8-only-for-latex-files.md) - Fully Support UTF-8 Only For LaTeX Files +* [ADR-0006](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0006-only-translated-strings-in-language-file.md) - Only translated strings in language file +* [ADR-0007](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0007-human-readable-changelog.md) - Provide a human-readable changelog +* [ADR-0008](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0008-use-public-final-instead-of-getters.md) - Use public final instead of getters to offer access to immutable variables +* [ADR-0009](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0009-use-plain-junit5-for-testing.md) - Use Plain JUnit5 for advanced test assertions +* [ADR-0010](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/0010-use-h2-as-internal-database.md) - Use H2 as Internal SQL Database + +For new ADRs, please use [template.md](https://github.com/JabRef/jabref/tree/3b3716b1e05a0d3273c886e102a8efe5e96472e0/docs/adr/template.md) as basis. More information on MADR is available at [https://adr.github.io/madr/](https://adr.github.io/madr/). General information about architectural decision records is available at [https://adr.github.io/](https://adr.github.io/). + +## FAQ + +* Q: I get `java: package org.jabref.logic.journals does not exist`. + + A: You have to ignore `buildSrc/src/main` as source directory in IntelliJ as indicated in our [setup guide](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace). + + Also filed as IntelliJ issue [IDEA-240250](https://youtrack.jetbrains.com/issue/IDEA-240250). diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index ef2d6d1dc74..a3836d7d6ba 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,20 +1,21 @@ # Table of contents * [Overview on Developing](README.md) - * [Contributing](contributing.md) -* [Architectural Decisions](adr/README.md) -* Getting into the code - * [Set up a local workspace](guidelines-for-setting-up-a-local-workspace.md) - * [High-level documentation](high-level-documentation.md) - * [How to test](testing.md) - * [Code Howtos](code-howtos.md) - * [JabRef's development strategy](development-strategy.md) -* Advanced reading - * [Code Quality](code-quality.md) - * [Recommendations for UI design](ui-recommendations.md) - * [Custom SVG icons](custom-svg-icons.md) - * [Creating a binary and debug it](jpackage.md) +* [Contributing](contributing.md) +* [Architectural Decisions](adr.md) +* [Getting into the code](getting-into-the-code/README.md) + * [Set up a local workspace](getting-into-the-code/guidelines-for-setting-up-a-local-workspace.md) + * [High-level documentation](getting-into-the-code/high-level-documentation.md) + * [How to test](getting-into-the-code/testing.md) + * [Code Howtos](getting-into-the-code/code-howtos.md) + * [JabRef's development strategy](getting-into-the-code/development-strategy.md) +* [Advanced reading](advanced-reading/README.md) + * [Code Quality](advanced-reading/code-quality.md) + * [Recommendations for UI design](advanced-reading/ui-recommendations.md) + * [Custom SVG icons](advanced-reading/custom-svg-icons.md) + * [Creating a binary and debug it](advanced-reading/jpackage.md) * [JabRef and Software Engineering](teaching.md) -* Readings on Coding - * [Readings on JavaFX](javafx.md) - * [Useful development tooling](tools.md) +* [Readings on Coding](readings-on-coding/README.md) + * [Readings on JavaFX](readings-on-coding/javafx.md) + * [Useful development tooling](readings-on-coding/tools.md) + diff --git a/docs/adr.md b/docs/adr.md new file mode 100644 index 00000000000..7db3ad33287 --- /dev/null +++ b/docs/adr.md @@ -0,0 +1,6 @@ +# Architectural Decisions + +This directory contains the architectural decisions for JabRef. + +For new ADRs, please use [template.md](adr/template.md) as basis. More information on the used format is available at [https://adr.github.io/madr/](https://adr.github.io/madr/). General information about architectural decision records is available at [https://adr.github.io/](https://adr.github.io/). + diff --git a/docs/adr/0004-use-mariadb-connector.md b/docs/adr/0004-use-mariadb-connector.md index 2085113a0a3..31b4b6604d6 100644 --- a/docs/adr/0004-use-mariadb-connector.md +++ b/docs/adr/0004-use-mariadb-connector.md @@ -30,3 +30,4 @@ The [MySQL Connector](https://www.mysql.com/de/products/connector/) is distribut * Good, because it stems from the same development team than MySQL * Bad, because the "Universal FOSS Exception" makes licensing more complicated. + diff --git a/docs/adr/0006-only-translated-strings-in-language-file.md b/docs/adr/0006-only-translated-strings-in-language-file.md index 1aada8966eb..2fd3ccfbc16 100644 --- a/docs/adr/0006-only-translated-strings-in-language-file.md +++ b/docs/adr/0006-only-translated-strings-in-language-file.md @@ -44,3 +44,4 @@ Chosen option: "Only translated strings in language file", because comes out bes * Related to [ADR-0001](0001-use-crowdin-for-translations.md). + diff --git a/docs/adr/README.md b/docs/adr/README.md deleted file mode 100644 index fbbb48cbc28..00000000000 --- a/docs/adr/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Architectural Decisions - -This directory contains the architectural decisions for JabRef. - -For new ADRs, please use [template.md](template.md) as basis. More information on the used format is available at [https://adr.github.io/madr/](https://adr.github.io/madr/). General information about architectural decision records is available at [https://adr.github.io/](https://adr.github.io/). - diff --git a/docs/adr/template.md b/docs/adr/template.md index 22d77697e71..b07f46e2eb0 100644 --- a/docs/adr/template.md +++ b/docs/adr/template.md @@ -1,10 +1,10 @@ # \[short title of solved problem and solution\] -* Status: \[proposed \| rejected \| accepted \| deprecated \| … \| superseded by [ADR-0005](https://github.com/JabRef/jabref/tree/8c07a88a823a84aebe987cdb717f318ed00a872d/docs/adr/0005-example.md)\] -* Deciders: \[list everyone involved in the decision\] -* Date: \[YYYY-MM-DD when the decision was last updated\] +* Status: \[proposed \| rejected \| accepted \| deprecated \| … \| superseded by [ADR-0005](0005-fully-support-utf8-only-for-latex-files.md)\] +* Deciders: \[list everyone involved in the decision\] +* Date: \[YYYY-MM-DD when the decision was last updated\] -Technical Story: \[description \| ticket/issue URL\] +Technical Story: \[description \| ticket/issue URL\] ## Context and Problem Statement @@ -14,14 +14,14 @@ Technical Story: \[description \| ticket/issue URL\] * \[driver 1, e.g., a force, facing concern, …\] * \[driver 2, e.g., a force, facing concern, …\] -* … +* … ## Considered Options * \[option 1\] * \[option 2\] * \[option 3\] -* … +* … ## Decision Outcome @@ -41,33 +41,33 @@ Chosen option: "\[option 1\]", because \[justification. e.g., only option, which ### \[option 1\] -\[example \| description \| pointer to more information \| …\] +\[example \| description \| pointer to more information \| …\] * Good, because \[argument a\] * Good, because \[argument b\] * Bad, because \[argument c\] -* … +* … ### \[option 2\] -\[example \| description \| pointer to more information \| …\] +\[example \| description \| pointer to more information \| …\] * Good, because \[argument a\] * Good, because \[argument b\] * Bad, because \[argument c\] -* … +* … ### \[option 3\] -\[example \| description \| pointer to more information \| …\] +\[example \| description \| pointer to more information \| …\] * Good, because \[argument a\] * Good, because \[argument b\] * Bad, because \[argument c\] -* … +* … ## Links -* \[Link type\] \[Link to ADR\] -* … +* \[Link type\] \[Link to ADR\] +* … diff --git a/docs/advanced-reading/README.md b/docs/advanced-reading/README.md new file mode 100644 index 00000000000..ed248e7ce51 --- /dev/null +++ b/docs/advanced-reading/README.md @@ -0,0 +1,2 @@ +# Advanced reading + diff --git a/docs/code-quality.md b/docs/advanced-reading/code-quality.md similarity index 83% rename from docs/code-quality.md rename to docs/advanced-reading/code-quality.md index 5739c3629eb..415b8e65372 100644 --- a/docs/code-quality.md +++ b/docs/advanced-reading/code-quality.md @@ -8,7 +8,8 @@ We monitor the general source code quality at three places: We strongly recommend to read following two books on code quality: -* [Java by Comparison](https://github.com/JabRef/jabref/tree/c81740b3818c7f9311a6d7ff063243e672c821b4/docs/java.by-comparison.com) is a book by three JabRef developers which focuses on code improvements close to single statements. It is fast to read and one gains much information from each recommendation discussed in the book. +* [Java by Comparison](http://java.by-comparison.com) is a book by three JabRef developers which focuses on code improvements close to single statements. It is fast to read and one gains much information from each recommendation discussed in the book. * [Effective Java](https://www.oreilly.com/library/view/effective-java-3rd/9780134686097/) is the standard book for advanced Java programming. Did you know that `enum` is the [recommended way to enforce a singleton instance of a class](https://learning.oreilly.com/library/view/effective-java-3rd/9780134686097/ch2.xhtml#lev3)? Did you know that one should [refer to objects by their interfaces](https://learning.oreilly.com/library/view/effective-java-3rd/9780134686097/ch9.xhtml#lev64)? -The principles we follow to ensure high code quality in JabRef is stated at our [Development Strategy](development-strategy.md). +The principles we follow to ensure high code quality in JabRef is stated at our [Development Strategy](../getting-into-the-code/development-strategy.md). + diff --git a/docs/custom-svg-icons.md b/docs/advanced-reading/custom-svg-icons.md similarity index 100% rename from docs/custom-svg-icons.md rename to docs/advanced-reading/custom-svg-icons.md diff --git a/docs/advanced-reading/jpackage.md b/docs/advanced-reading/jpackage.md new file mode 100644 index 00000000000..8d3d79df356 --- /dev/null +++ b/docs/advanced-reading/jpackage.md @@ -0,0 +1,38 @@ +# Creating a binary and debug it + +JabRef uses [jpackage](https://docs.oracle.com/en/java/javase/14/jpackage/) to build binary application bundles and installers for Windows, Linux, and Mac OS X. +For Gradle, we use the [Badass JLink Plugin](https://badass-jlink-plugin.beryx.org/releases/latest/). + +## Build Windows binaries locally + +Preparation: Install [WiX Toolset](https://wixtoolset.org/) + + 1. Open administrative shell + 2. Use [Chocolatey](https://chocolatey.org/) to install it: `choco install wixtoolset` + +Create the application image: + +```./gradlew -PprojVersion="5.0.50013" -PprojVersionInfo="5.0-ci.13--2020-03-05--c8e5924" jpackageImage``` + +Create the installer: + +`./gradlew -PprojVersion="5.0.50013" -PprojVersionInfo="5.0-ci.13--2020-03-05--c8e5924" jpackage` + +## Debugging jpackage installations + +Sometimes issues with modularity only arise in the installed version and do not occur if you run from source. Using remote debugging, it's still possible to hook your IDE into the running JabRef application to enable debugging. + +### Debugging on Windows + +1. Open `build.gradle`, under jlink options remove `--strip-debug` +2. Build using `jpackageImage` (or let the CI build a new version) +3. Modify the `build\image\JabRef\runtime\bin\Jabref.bat` file, replace the last line with + + ```text + pushd %DIR% & %JAVA_EXEC% -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -p "%~dp0/../app" -m org.jabref/org.jabref.JabRefLauncher %* & popd + ``` + +4. Open your IDE and add a "Remote Debugging Configuration" for `localhost:8000` +5. Start JabRef by running the above bat file +6. Connect with your IDE using remote debugging + diff --git a/docs/ui-recommendations.md b/docs/advanced-reading/ui-recommendations.md similarity index 100% rename from docs/ui-recommendations.md rename to docs/advanced-reading/ui-recommendations.md diff --git a/docs/contributing.md b/docs/contributing.md index ef5d785f063..99d03918f09 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -4,8 +4,7 @@ See [JabRef's contribution guide](https://github.com/JabRef/jabref/blob/master/C In case you aim for contributing user documentation, head to the [JabRef user documentation repository](https://github.com/JabRef/user-documentation). -For improving developer's documentation, go on at the [docs/ subdirectory of JabRef's code](https://github.com/JabRef/jabref/tree/master/docs) and edit the file. -GitHub offers a good guide at [Editing files in another user's repository](https://help.github.com/en/github/managing-files-in-a-repository/editing-files-in-another-users-repository). +For improving developer's documentation, go on at the [docs/ subdirectory of JabRef's code](https://github.com/JabRef/jabref/tree/master/docs) and edit the file. GitHub offers a good guide at [Editing files in another user's repository](https://help.github.com/en/github/managing-files-in-a-repository/editing-files-in-another-users-repository). In case you use some gitbook special features and you want to test them, checkout JabRef's code locally, and execute following steps: @@ -13,4 +12,5 @@ In case you use some gitbook special features and you want to test them, checkou 2. `cd docs` 3. `gitbook serve` -Then, you can see a near-to-reality rendering of the development documentation at . +Then, you can see a near-to-reality rendering of the development documentation at [http://localhost:4000](http://localhost:4000). + diff --git a/docs/getting-into-the-code/README.md b/docs/getting-into-the-code/README.md new file mode 100644 index 00000000000..b2f10067f15 --- /dev/null +++ b/docs/getting-into-the-code/README.md @@ -0,0 +1,2 @@ +# Getting into the code + diff --git a/docs/code-howtos.md b/docs/getting-into-the-code/code-howtos.md similarity index 96% rename from docs/code-howtos.md rename to docs/getting-into-the-code/code-howtos.md index 9e747de41ea..da68451bef6 100644 --- a/docs/code-howtos.md +++ b/docs/getting-into-the-code/code-howtos.md @@ -30,6 +30,7 @@ Principles: Localization.lang("Something went wrong...", ioe); } ``` + * Never, ever throw and catch `Exception` or `Throwable` * Errors should only be logged when they are finally caught \(i.e., logged only once\). See **Logging** for details. * If the Exception message is intended to be shown to the User in the UI \(see below\) provide also a localizedMessage \(see `JabRefException`\). @@ -45,7 +46,9 @@ To show error message two different ways are usually used in JabRef: * showing an error dialog * updating the status bar at the bottom of the main window -_TODO: Usage of status bar and Swing Dialogs_ +```text +TODO: Usage of status bar and Swing Dialogs +``` ## Using the EventSystem @@ -138,7 +141,7 @@ JabRef uses the logging facade [SLF4j](https://www.slf4j.org/). All log messages ## Using Localization correctly -_\(More information about this topic from the translator side is provided under this link:_ [_Translating JabRef Interface_](https://github.com/JabRef/jabref/wiki/Translating-JabRef-Interface) _about the JabRef interface and_ [_Translating JabRef Help_](https://github.com/JabRef/jabref/wiki/Translating-JabRef-Help) _about the JabRef help files\)_ +More information about this topic from the translator side is provided at [Translating JabRef Interface](https://docs.jabref.org/faqcontributing/how-to-translate-the-ui). All labeled UI elements, descriptions and messages shown to the user should be localized, i.e., should be displayed in the chosen language. @@ -170,7 +173,7 @@ General hints: The tests check whether translation strings appear correctly in the resource bundles. -1. Add new `Localization.lang("KEY")` to Java file. Run the `LocalizationConsistencyTest`under (src/test/org.jabref.logic.l10n) +1. Add new `Localization.lang("KEY")` to Java file. Run the `LocalizationConsistencyTest`under \(src/test/org.jabref.logic.l10n\) 2. Tests fail. In the test output a snippet is generated which must be added to the English translation file. There is also a snippet generated for the non-English files, but this is irrelevant. 3. Add snippet to English translation file located at `src/main/resources/l10n/JabRef_en.properties` 4. Please do not add tranlsations for other languages direclty in the properties. They will be overwritten by [Crowdin](https://crowdin.com/project/jabref) @@ -179,7 +182,7 @@ The tests check whether translation strings appear correctly in the resource bun We try to build a cleanup mechanism based on formatters. The idea is that we can register these actions in arbitrary places, e.g., onSave, onImport, onExport, cleanup, etc. and apply them to different fields. The formatters themself are independent of any logic and therefore easy to test. -Example: [PageNumbersFormatter](https://github.com/JabRef/jabref/blob/master/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/PageNumbersFormatter.java) +Example: [NormalizePagesFormatter](https://github.com/JabRef/jabref/blob/master/src/main/java/org/jabref/logic/formatter/bibtexfields/NormalizePagesFormatter.java) ## Drag and Drop diff --git a/docs/development-strategy.md b/docs/getting-into-the-code/development-strategy.md similarity index 96% rename from docs/development-strategy.md rename to docs/getting-into-the-code/development-strategy.md index 29b5bcaac66..541a5dfe784 100644 --- a/docs/development-strategy.md +++ b/docs/getting-into-the-code/development-strategy.md @@ -1,4 +1,4 @@ -# JabRef's Development Strategy +# JabRef's development strategy We aim to keep up to high-quality code standards and use code quality tools wherever possible. @@ -10,7 +10,7 @@ To ensure high code-quality, * 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/master/DEVELOPERS). -Read on about our automated quality checks at [Code Quality](code-quality.md). +Read on about our automated quality checks at [Code Quality](../advanced-reading/code-quality.md). ## Continuous integration diff --git a/docs/guidelines-for-setting-up-a-local-workspace.md b/docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace.md similarity index 74% rename from docs/guidelines-for-setting-up-a-local-workspace.md rename to docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace.md index 94faa6196e0..95b55e28b9c 100644 --- a/docs/guidelines-for-setting-up-a-local-workspace.md +++ b/docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace.md @@ -10,18 +10,17 @@ In case you know how to install JDK14 and to fork JabRef's code, For a complete step-by-step guide for Linux using IntellJ IDEA as the IDE, have a look at the following video instructions: - [![YouTube video showing the step-by-step guide](https://img.youtube.com/vi/JkFVJ6p0urw/mqdefault.jpg)](https://youtu.be/JkFVJ6p0urw) +[![YouTube video showing the step-by-step guide](https://img.youtube.com/vi/JkFVJ6p0urw/mqdefault.jpg)](https://youtu.be/JkFVJ6p0urw) ## Prerequisites -This section list the prerequisites you need to get started to develop JabRef. -After this section, you are ready to get the code. +This section list the prerequisites you need to get started to develop JabRef. After this section, you are ready to get the code. ### Java Development Kit 14 A working Java 14 installation is required. In the command line \(terminal in Linux, cmd in Windows\) run `javac -version` and make sure that the reported version is Java 14 \(e.g `javac 14`\). If `javac` is not found or a wrong version is reported, check your PATH environment variable, your `JAVA_HOME` environment variable or install the most recent JDK. -Download the JDK from . On Windows, you can execute `choco install openjdk` (requires [installation of chocolatey - a package manager for Windows](https://chocolatey.org/install)). +Download the JDK from [https://jdk.java.net/](https://jdk.java.net/). On Windows, you can execute `choco install openjdk` \(requires [installation of chocolatey - a package manager for Windows](https://chocolatey.org/install)\). ### GitHub Account @@ -33,15 +32,13 @@ Proposals for account names: * Use your last name prefixed by the first letter of your first name. Example: `okopp` * Use `firstname.lastname`. Example: `oliver.kopp` -You can hide your email adress by following the recommendations at . +You can hide your email adress by following the recommendations at [https://saraford.net/2017/02/19/how-to-hide-your-email-address-in-your-git-commits-but-still-get-contributions-to-show-up-on-your-github-profile-050/](https://saraford.net/2017/02/19/how-to-hide-your-email-address-in-your-git-commits-but-still-get-contributions-to-show-up-on-your-github-profile-050/). -Most developers, though, do not hide their email adress. They use one mich may get public. -Mostly, they create a new email account for development only. -That account then be used for develoment mailing lists, mail exchange with other developers, etc. +Most developers, though, do not hide their email adress. They use one mich may get public. Mostly, they create a new email account for development only. That account then be used for develoment mailing lists, mail exchange with other developers, etc. Examples: -* Same login as in GitHub (see above). Example: `koppor@gmail.com` +* Same login as in GitHub \(see above\). Example: `koppor@gmail.com` * "`it`" in the name. Example: `kopp.it@gmail.com` * Use the university login. Example: `st342435@stud.uni-stuttgart.de` @@ -51,19 +48,22 @@ It is strongly recommend that you have git installed. * In Debian-based distros: `sudo apt-get install git` * In Windows: [Download the installer](http://git-scm.com/download/win) and install it. - Using chocolatey, you can run `choco install git.install -y --params "/GitAndUnixToolsOnPath /WindowsTerminal` to a) install git and b) have linux commands such as `grep` available in your `PATH`. + + Using chocolatey, you can run `choco install git.install -y --params "/GitAndUnixToolsOnPath /WindowsTerminal` to a\) install git and b\) have linux commands such as `grep` available in your `PATH`. + For more advanced tooling, you may use [Fork - a fast and friendly git client for Mac and Windows](https://git-fork.com/): `choco install git-fork`. + * [official installation instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) ### IDE -We suggest [IntelliJ IDEA](https://www.jetbrains.com/idea/) or [Eclipse (for advanced users)](https://eclipse.org/) \(`2020-03` or newer\). +We suggest [IntelliJ IDEA](https://www.jetbrains.com/idea/) or [Eclipse \(for advanced users\)](https://eclipse.org/) \(`2020-03` or newer\). -Under Ubuntu Linux, you can follow the [documentation from the Ubuntu Community](https://help.ubuntu.com/community/EclipseIDE#Download_Eclipse) or the [step-by-step guideline from Krizna](https://github.com/JabRef/jabref/tree/be9c788de804c2bd9e3abaf76b082b6b2e82e66f/docs/www.krizna.com/ubuntu/install-eclipse-in-ubuntu-12-04/README.md) to install Eclipse. Under Windows, download it from [www.eclipse.org](http://www.eclipse.org/downloads/) and run the installer. +Under Ubuntu Linux, you can follow the [documentation from the Ubuntu Community](https://help.ubuntu.com/community/EclipseIDE#Download_Eclipse) or the [step-by-step guideline from Krizna](https://www.krizna.com/ubuntu/install-eclipse-in-ubuntu-12-04/) to install Eclipse. Under Windows, download it from [www.eclipse.org](http://www.eclipse.org/downloads/) and run the installer. ### Other Tooling -See our [tool recommendations](tools.md). +See our [tool recommendations](../readings-on-coding/tools.md). ## Get the code @@ -74,7 +74,7 @@ This section explains how you get the JabRef code onto your machine in a form al 1. Log into your GitHub account 2. Go to [https://github.com/JabRef/jabref](https://github.com/JabRef/jabref) 3. Create a fork by clicking at fork button on the right top corner -4. A fork repository will be created under your account \([https://github.com/YOUR\_USERNAME/jabref](https://github.com/YOUR_USERNAME/jabref)\) +4. A fork repository will be created under your account `https://github.com/YOUR\_USERNAME/jabref`. ### Clone your forked repository on your local machine @@ -87,9 +87,7 @@ This section explains how you get the JabRef code onto your machine in a form al ## Configure your IDE -These steps are very important. -They allow you to focus on the content and ensure that the code formatting always goes well. -Did you know that [IntelliJ allows for reformatting selected code](https://www.jetbrains.com/help/idea/reformat-and-rearrange-code.html#reformat_code) if you press Ctrl+Alt+L? +These steps are very important. They allow you to focus on the content and ensure that the code formatting always goes well. Did you know that [IntelliJ allows for reformatting selected code](https://www.jetbrains.com/help/idea/reformat-and-rearrange-code.html#reformat_code) if you press Ctrl+Alt+L? ### Setup for IntelliJ IDEA @@ -98,21 +96,25 @@ IntelliJ IDEA fully supports Gradle as a build tool, but also has an internal bu To configure IntelliJ IDEA for developing JabRef, you should first ensure that you have enabled both bundled plugins _Gradle_ and _Gradle Extension_ * Navigate to **File \| Settings \| Plugins \| Installed** and check that you have + the _Gradle_ and _Gradle Extension_ enabled. After that, you can open `jabref/build.gradle` as a project. It is crucial that Java 14 is used consistently for the JabRef project which includes ensuring the right settings for your project structure, Gradle build, and run configurations. * Ensure you have a Java 14 SDK configured by navigating to + **File \| Project Structure \| Platform Settings \| SDKs**. If you don't have one, add a new Java JDK and point it to the + location of a JDK 14. + * Navigate to **File \| Project Structure \| Project** and ensure that the projects' SDK is Java 14 * Navigate to **File \| Settings \| Build, Execution, Deployment \| Build Tools \| Gradle** and select the Java 14 SDK as + the Gradle JVM at the bottom. To prepare IntelliJ's build system two additional steps are required -* Navigate to **File \| Settings \| Build, Execution, Deployment \| Compiler \| Java Compiler**, and under - "Override compiler parameters per-module" add \(\[+\]\) the following compiler arguments for the `JabRef.main` module: +* Navigate to **File \| Settings \| Build, Execution, Deployment \| Compiler \| Java Compiler**, and under "Override compiler parameters per-module" add \(\[+\]\) the following compiler arguments for the `JabRef.main` module: ```text --add-exports=javafx.controls/com.sun.javafx.scene.control=org.jabref @@ -123,22 +125,27 @@ To prepare IntelliJ's build system two additional steps are required **File \| Settings \| Build, Execution, Deployment \| Compiler \| Annotation processors** and check "Enable annotation processing" +To have autoformat working properly in the context of line wrapping, "Wrap at right margin" has to be disabled as shown below. Details are found in [IntelliJ issue 240517](https://youtrack.jetbrains.com/issue/IDEA-240517). + +![Disable wrapping at right margin to prevent JavaDoc to be wrapped](../.gitbook/assets/grafik.png) + #### Using Gradle from within IntelliJ IDEA Ensuring JabRef builds with Gradle should always the first step because, e.g. it generates additional sources that are required for compiling the code. After adjusting all settings mentioned earlier, your first step should be to * Open the Gradle Tool Window with the small button that can usually be found on the right side of IDEA or navigate to + **View \| Tool Windows \| Gradle**. + * In the Gradle Tool Window, press the "Reimport All Gradle Projects" button to ensure that all settings are up-to-date + with the setting changes. After that, you can use the Gradle Tool Window to build all parts JabRef and run it. To do so, expand the JabRef project in the Gradle Tool Window and navigate to Tasks. From there, you can * Build and run JabRef by double-clicking **JabRef \| Tasks \| application \| run**. -After that a new entry called "jabref \[run\]" will appear in the run configurations. -Now you can also select "jabref \[run\]" and either run or debug the application from within IntelliJ. -You can run any other development task in a similar way. Equivalently, this can also be executed from the terminal by running `./gradlew run`. +After that a new entry called "jabref \[run\]" will appear in the run configurations. Now you can also select "jabref \[run\]" and either run or debug the application from within IntelliJ. You can run any other development task in a similar way. Equivalently, this can also be executed from the terminal by running `./gradlew run`. #### Using IntelliJ's internal build system @@ -147,9 +154,12 @@ You should use IntelliJ IDEA's internal build system for compiling and running J To use IntelliJ IDEA's internal build system when you build JabRef through **Build \| Build Project** or use the provided "JabRef Main" run configuration, ensure that * in **File \| Settings \| Build, Execution, Deployment \| Build Tools \| Gradle** the setting "Build and run using" and + "Test using" is set to "IntelliJ IDEA". + * Ignore the Gradle project "buildSrc": - ![Ignore the Gradle project "buildSrc"](intellij-gradle-config-ignore-buildSrc.png) + + ![Ignore the Gradle project "buildSrc"](../.gitbook/assets/intellij-gradle-config-ignore-buildSrc.png) Essentially, you now have the best of both worlds: You can run Gradle tasks using the Gradle Tool Window and unless you haven't made changes to input files that generate sources, you can compile and run with IntelliJ's faster internal build system. @@ -158,36 +168,38 @@ Essentially, you now have the best of both worlds: You can run Gradle tasks usin Contributions to JabRef's source code need to have a code formatting that is consistent with existing source code. For that purpose, JabRef provides code-style and check-style definitions. * Install the [CheckStyle-IDEA plugin](http://plugins.jetbrains.com/plugin/1065?pr=idea), it can be found via the plug-in repository: - 1. Navigate to **File \| Settings \| Plugins \| Marketplace** and search for "Checkstyle" and choose "CheckStyle-IDEA" - 2. Close the settings afterwards and restart IntelliJ + 1. Navigate to **File \| Settings \| Plugins \| Marketplace** and search for "Checkstyle" and choose "CheckStyle-IDEA" + 2. Close the settings afterwards and restart IntelliJ * Go to **File \| Settings \| Editor \| Code Style** * Click on the settings wheel \(next to the scheme chooser\), then click "Import Scheme" * Select the IntelliJ configuration file `config/IntelliJ Code Style.xml` * Go to **File \| Settings \| Checkstyle \| Configuration File** - 1. Import the CheckStyle configuration file by clicking the \[+\] button - 2. For the description provide "JabRef" - 3. Click "Browse" and choose `config/checkstyle/checkstyle.xml` - 4. Check "Store relative to project location" - 5. Click "Next" and "Finish" - 6. Activate the CheckStyle configuration file by ticking it in the list - 7. Ensure that the latest CheckStyle version is selected (8.32 or higher) - 8. Set the "Scan Scope" to "Only Java sources (including tests) - 9. Save settings by clicking "OK" - 10. Your configuration should now look like this: - ![checkstyle settings](images/intellij-checkstyle-settings.png) + 1. Import the CheckStyle configuration file by clicking the \[+\] button + 2. For the description provide "JabRef" + 3. Click "Browse" and choose `config/checkstyle/checkstyle.xml` + 4. Check "Store relative to project location" + 5. Click "Next" and "Finish" + 6. Activate the CheckStyle configuration file by ticking it in the list + 7. Ensure that the latest CheckStyle version is selected \(8.32 or higher\) + 8. Set the "Scan Scope" to "Only Java sources \(including tests\) + 9. Save settings by clicking "OK" + 10. Your configuration should now look like this: + + ![checkstyle settings](../.gitbook/assets/intellij-checkstyle-settings.png) #### Troubleshooting when using both IDEA and Eclipse If you have configured Eclipse for the same project \(the required steps are described below\), then the additionally added file `Log4jPlugins.java` must be excluded from the compilation process, otherwise an error will occur during the compilation of the project: * **File \| Settings \| Build, Execution, Deployment \| Compiler \| Excludes** and add the following file to the + list \(\[+\]\), in order to exclude it: + * `src/main/java/org/jabref/gui/logging/plugins/Log4jPlugins.java` ### Setup for Eclipse -Make sure your Eclipse installation us up to date, Eclipse 2020-03 or newer is required. -For Eclipse 2020-03 you need to install [jdk14 support](https://marketplace.eclipse.org/content/java-14-support-eclipse-2020-03-415) +Make sure your Eclipse installation us up to date, Eclipse JEE 2020-03 or newer is required. For Eclipse 2020-03 you need to install [jdk14 support](https://marketplace.eclipse.org/content/java-14-support-eclipse-2020-03-415) 1. Run `./gradlew run` to generate all resources and to check if JabRef runs. * The JabRef GUI should finally appear. @@ -202,7 +214,7 @@ For Eclipse 2020-03 you need to install [jdk14 support](https://marketplace.ecli 5. Create a run/debug configuration for the main class `org.jabref.JabRefLauncher` and/or for `org.jabref.JabRefMain` \(both can be used equivalently\) * In the tab "Arguments" of the run/debug configuration, enter the following runtime VM arguments: - ```text + ```text --patch-module test=fastparse_2.12-1.0.0.jar --patch-module test2=fastparse-utils_2.12-1.0.0.jar --patch-module test3=sourcecode_2.12-0.1.4.jar @@ -221,15 +233,11 @@ For Eclipse 2020-03 you need to install [jdk14 support](https://marketplace.ecli --add-exports javafx.graphics/com.sun.javafx.css=org.controlsfx.controls --add-exports javafx.controls/com.sun.javafx.scene.control.behavior=com.jfoenix --add-exports com.oracle.truffle.regex/com.oracle.truffle.regex=org.graalvm.truffle - --patch-module org.jabref=build\resources\main - ``` - -6. Optional: Install the [e\(fx\)clipse plugin](http://www.eclipse.org/efxclipse/index.html) from the Eclipse marketplace: - 1. Help -> Eclipse Marketplace... -> Search tab - 2. Enter "e\(fx\)clipse" in the search dialogue - 3. Click "Go" - 4. Click "Install" button next to the plugin - 5. Click "Finish" + --patch-module org.jabref=build/resources/main + ``` + + * In the tab "Dependencies" of the run/debug configuration tick the checkbox "Exclude test code" +6. Optional: Install the [e\(fx\)clipse plugin](http://www.eclipse.org/efxclipse/index.html) from the Eclipse marketplace: 1. Help -> Eclipse Marketplace... -> Search tab 2. Enter "e\(fx\)clipse" in the search dialogue 3. Click "Go" 4. Click "Install" button next to the plugin 5. Click "Finish" 7. Now you can build and run/debug the application by either using "JabRefLauncher" or "JabRefMain". This is the recommended way, since the application starts quite fast. ## Final comments diff --git a/docs/high-level-documentation.md b/docs/getting-into-the-code/high-level-documentation.md similarity index 100% rename from docs/high-level-documentation.md rename to docs/getting-into-the-code/high-level-documentation.md diff --git a/docs/testing.md b/docs/getting-into-the-code/testing.md similarity index 72% rename from docs/testing.md rename to docs/getting-into-the-code/testing.md index 37c2a7164ee..f88560233f9 100644 --- a/docs/testing.md +++ b/docs/getting-into-the-code/testing.md @@ -6,19 +6,19 @@ To quickly host a local PostgreSQL database, execute following statement: -```terminal +```text docker run -d -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p 5432:5432 --name db postgres:10 postgres -c log_statement=all ``` -Set the environment variable `DBMS` to `postgres` (or leave it unset) +Set the environment variable `DBMS` to `postgres` \(or leave it unset\) -Then, all DBMS Tests (annotated with `@org.jabref.testutils.category.DatabaseTest`) run properly. +Then, all DBMS Tests \(annotated with `@org.jabref.testutils.category.DatabaseTest`\) run properly. ### MySQL A MySQL DBMS can be started using following command: -```terminal +```text docker run -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=jabref -p 3800:3307 mysql:8.0 --port=3307 ``` diff --git a/docs/jpackage.md b/docs/jpackage.md deleted file mode 100644 index 325970b58e9..00000000000 --- a/docs/jpackage.md +++ /dev/null @@ -1,39 +0,0 @@ -# jpackage - -JabRef uses [jpackage](https://jdk.java.net/jpackage/) to build binary distributions for Windows, Linux, and Mac OS X. - -## Build Windows binaries locally - -Preparation: - -1. Install [WiX Toolset](https://wixtoolset.org/) - 1. Open administrative shell - 2. Use [Chocolatey](https://chocolatey.org/) to install it: `choco install wixtoolset` -2. Open [git bash](https://superuser.com/a/1053657/138868) -3. Get [JDK14](https://openjdk.java.net/projects/jdk/14/): `wget https://download.java.net/java/GA/jdk14/076bab302c7b4508975440c56f6cc26a/36/GPL/openjdk-14_windows-x64_bin.zip` -4. Extract JDK14: `unzip openjdk-14_windows-x64_bin.zip` - -Compile: - -1. `export BADASS_JLINK_JPACKAGE_HOME=jdk-14/` -2. `./gradlew -PprojVersion="5.0.50013" -PprojVersionInfo="5.0-ci.13--2020-03-05--c8e5924" jlinkZip` -3. `./gradlew -PprojVersion="5.0.50013" -PprojVersionInfo="5.0-ci.13--2020-03-05--c8e5924" jpackage` - -## Debugging jpackage installations - -Sometimes issues with modularity only arise in the installed version and do not occur if you run from source. Using remote debugging, it's still possible to hook your IDE into the running JabRef application to enable debugging. - -### Debugging on Windows - -1. Open `build.gradle`, under jlink options remove `--strip-debug` -2. Build or let the CI build a new version -3. Download the modified version or portable version go to `\JabRef\runtime\bin\Jabref.bat` -4. Modify the bat file, replace the last line with - - ```cmd - pushd %DIR% & %JAVA_EXEC% -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -p "%~dp0/../app" -m org.jabref/org.jabref.JabRefLauncher %* & popd - ``` - -5. Open your IDE and add a "Remote Debugging Configuration" for `localhost:8000` -6. Start JabRef from the bat file -7. Connect with your IDE using remote debugging diff --git a/docs/readings-on-coding/README.md b/docs/readings-on-coding/README.md new file mode 100644 index 00000000000..6108184a6d3 --- /dev/null +++ b/docs/readings-on-coding/README.md @@ -0,0 +1,2 @@ +# Readings on Coding + diff --git a/docs/javafx.md b/docs/readings-on-coding/javafx.md similarity index 94% rename from docs/javafx.md rename to docs/readings-on-coding/javafx.md index 06721363efa..8768d897f45 100644 --- a/docs/javafx.md +++ b/docs/readings-on-coding/javafx.md @@ -1,4 +1,4 @@ -# JavaFX +# Readings on JavaFX JabRef's recommendations about JavaFX @@ -7,7 +7,7 @@ JabRef's recommendations about JavaFX The goal of the MVVM architecture is to separate the state/behavior from the appearance of the ui. This is archived by dividing JabRef into different layers, each having a clear responsibility. * The _Model_ contains the business logic and data structures. These aspects are again encapsulated in the _logic_ and _model_ package, respectively. -* The _View_ controls the appearance and structure of the UI. It is usually defined in a _FXML_ file. +* The _View_ controls the appearance and structure of the UI. It is usually defined in a _FXML_ file. * _View model_ converts the data from logic and model in a form that is easily usable in the gui. Thus it controls the state of the View. Moreover, the ViewModel contains all the logic needed to change the current state of the UI or perform an action. These actions are usually passed down to the _logic_ package, after some data validation. The important aspect is that the ViewModel contains all the ui-related logic but does _not_ have direct access to the controls defined in the View. Hence, the ViewModel can easily be tested by unit tests. * The _Controller_ initializes the view model and binds it to the view. In an ideal world all the binding would already be done directly in the FXML. But JavaFX's binding expressions are not yet powerful enough to accomplish this. It is important to keep in mind that the Controller should be as minimalistic as possible. Especially one should resist the temptation to validate inputs in the controller. The ViewModel should handle data validation! It is often convenient to load the FXML file directly from the controller. @@ -134,14 +134,14 @@ private void openJabrefWebsite() { ### View - FXML -The view consists a FXML file `MyDialog.fxml` which defines the structure and the layout of the UI. Moreover, the FXML file may be accompanied by a style file that should have the same name as the FXML file but with a `css` ending, e.g., `MyDialog.css`. It is recommended to use a graphical design tools like [SceneBuilder](http://gluonhq.com/labs/scene-builder/) to edit the FXML file. The tool [Scenic View](http://fxexperience.com/scenic-view/) is very helpful in debugging styling issues. +The view consists a FXML file `MyDialog.fxml` which defines the structure and the layout of the UI. Moreover, the FXML file may be accompanied by a style file that should have the same name as the FXML file but with a `css` ending, e.g., `MyDialog.css`. It is recommended to use a graphical design tools like [SceneBuilder](http://gluonhq.com/labs/scene-builder/) to edit the FXML file. The tool [Scenic View](https://github.com/JonathanGiles/scenic-view) is very helpful in debugging styling issues. ## Resources * [curated list of awesome JavaFX frameworks, libraries, books and etc...](https://github.com/mhrimaz/AwesomeJavaFX) * [ControlsFX](http://fxexperience.com/controlsfx/features/) amazing collection of controls -* [usage of icon fonts with JavaFX](http://aalmiray.github.io/ikonli/#_javafx) or [jIconFont](https://github.com/jIconFont/jiconfont-google_material_design_icons) or [fontawesomefx](https://bitbucket.org/Jerady/fontawesomefx/) -* [Undo manager](https://github.com/TomasMikula/UndoFX) +* [jIconFont](http://jiconfont.github.io/googlematerialdesignicons) or [fontawesomefx](https://bitbucket.org/Jerady/fontawesomefx/) +* [Undo manager](https://github.com/FXMisc/UndoFX) * [Docking manager](https://github.com/alexbodogit/AnchorFX) [or](https://github.com/RobertBColton/DockFX) * [additional bindings](https://github.com/lestard/advanced-bindings) or [EasyBind](https://github.com/TomasMikula/EasyBind) * [Kubed](https://github.com/hudsonb/kubed): data visualization \(inspired by d3\) diff --git a/docs/tools.md b/docs/readings-on-coding/tools.md similarity index 100% rename from docs/tools.md rename to docs/readings-on-coding/tools.md diff --git a/docs/teaching.md b/docs/teaching.md index a6e9c6726f8..b05a5365b2e 100644 --- a/docs/teaching.md +++ b/docs/teaching.md @@ -1,56 +1,47 @@ -# JabRef as Basis for Teaching Material +# JabRef and Software Engineering -JabRef can be used as a training object for software engineering. +With JabRef students can level-up their coding and GitHub skills. When taking part in JabRef development, one will learn modern Java coding practices, how code reviews work and how to properly address reviewing feedback. -As an instructor, please follow this checklist: +JabRef tries to achieve high code quality. This ultimately leads to improved software engineering knowledge of contributors. After contributing for JabRef, both coding and general software engienering skills will have increased. Our [development strategy](getting-into-the-code/development-strategy.md) provides more details. + +We recommend to start early and constantly, since students wirking earlier and more often, produce projects that are more correct, completed earlier at the same overall invested time [1](teaching.md#Ayaankazerouni). + +## Notes for instructors 1. Be aware that JabRef is run by volunteers. This implies that the development team cannot ensure to provide feedback on code within hours. 2. Be aware that from the first pull request to the final acceptance the typical time needed is two weeks. -3. Be aware that JabRef tries to achieve high code quality. This leads to code reviews requiring actions from the contributors. This also applies for code of students. Read on at our [Development Strategy](development-strategy.md) for more details. +3. Be aware that JabRef tries to achieve high code quality. This leads to code reviews requiring actions from the contributors. This also applies for code of students. Read on at our [Development Strategy](getting-into-the-code/development-strategy.md) for more details. 4. Choose tasks from one of the following boards. Write a comment on each issue so that it can be reserved for your course. - - Feature Board: - - Bug Board: + * Feature Board: [https://github.com/JabRef/jabref/projects/7](https://github.com/JabRef/jabref/projects/7) + * Bug Board: [https://github.com/JabRef/jabref/projects/5](https://github.com/JabRef/jabref/projects/5) 5. Be aware that the difficulty of bugs and feature vary. A task should be chosen with care. The JabRef team can help here: The majority of the team has experiences in teaching 6. Get in touch with the JabRef team to discuss details. We offer email, skype, [gitter.im](https://gitter.im/JabRef/jabref), discord. Get in touch with [@koppor](https://github.com/koppor/) to find the right channel and to start forming the success of your course. -For a near-to-perfect preparation and effect of the course, we ask you to get in touch with us **four weeks** in advance. Then, the JabRef team can a) learn about the starting skill level of the students, b) the aimed skill level at the end of the course, c) the amount of time the students are given to learn about and contribute to JabRef, d) check the [feature board](https://github.com/JabRef/jabref/projects/7) for appropriate tasks (and fill it as needed), e) recommend appropriate features. +For a near-to-perfect preparation and effect of the course, we ask you to get in touch with us **four weeks** in advance. Then, the JabRef team can a\) learn about the starting skill level of the students, b\) the aimed skill level at the end of the course, c\) the amount of time the students are given to learn about and contribute to JabRef, d\) check the [feature board](https://github.com/JabRef/jabref/projects/7) for appropriate tasks \(and fill it as needed\), e\) recommend appropriate features. -It is also possible to just direct students to our [Contribution Guide](https://github.com/JabRef/jabref/blob/master/CONTRIBUTING.md#contributing-guide). The learning effect may be lower as the time of the students has to be spent to a) learn about JabRef and b) select an appropriate issue. +It is also possible to just direct students to our [Contribution Guide](https://github.com/JabRef/jabref/blob/master/CONTRIBUTING.md#contributing-guide). The learning effect may be lower as the time of the students has to be spent to a\) learn about JabRef and b\) select an appropriate issue. -Since a huge fraction of software costs is spend on [software maintenance](https://en.wikipedia.org/wiki/Software_maintenance), adding new features also educates in that aspect: perfective maintenance[1](#LientzSwanson) is trained. When fixing bugs, corrective maintenance[1](#LientzSwanson) is trained. +Since a huge fraction of software costs is spend on [software maintenance](https://en.wikipedia.org/wiki/Software_maintenance), adding new features also educates in that aspect: perfective maintenance[1](teaching.md#LientzSwanson) is trained. When fixing bugs, corrective maintenance[2](teaching.md#LientzSwanson) is trained. ## Process for contributions There is no special process for student contributions. We want to discuss it nevertheless to increase awareness of the time required from starting the contribution until the inclusion in a release of JabRef. -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/). +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](images/contribution-process-reviews.svg)](images/contribution-process-reviews.svg) +[![process](.gitbook/assets/contribution-process-reviews.svg)](https://github.com/JabRef/jabref/tree/ed275b62fe7dac57a086e43802e36deb93c63e31/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. +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 [Unterstanding the GitHub flow](https://guides.github.com/introduction/flow/): -[![GitHub flow](images/github-flow.png)](images/github-flow.png) +[![GitHub flow](.gitbook/assets/github-flow.png)](https://github.com/JabRef/jabref/tree/ed275b62fe7dac57a086e43802e36deb93c63e31/docs/images/github-flow.png) ## Process for Java newcomers -Newcomers 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. +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](images/contribution-process-reviews-with-instructor.svg)](images/contribution-process-reviews-with-instructor.svg) +[![process with instructor](.gitbook/assets/contribution-process-reviews-with-instructor.svg)](https://github.com/JabRef/jabref/tree/ed275b62fe7dac57a086e43802e36deb93c63e31/docs/images/contribution-process-reviews-with-instructor.svg) ## Past courses @@ -58,19 +49,19 @@ This will help to reduce the load on the JabRef team and improve the quality of ### English -#### Harbin Institute of Technology (HIT), China +#### Harbin Institute of Technology \(HIT\), China Course: Open Source Software Development -- Summary: In this course, students will be introduced to the processes and tools specific to Open Source Software development, and they will analyze existing projects to understand the architecture and processes of these projects. Besides, students will attempt to contribute source code to a large existing Open Source Software project. -- Course offered in 2018 and 2019. Examples of merged pull requests: [4217](https://github.com/JabRef/jabref/pull/4217), [4255](https://github.com/JabRef/jabref/pull/4255), [4227](https://github.com/JabRef/jabref/pull/4227), [4260](https://github.com/JabRef/jabref/pull/4260), [5150](https://github.com/JabRef/jabref/pull/5150) +* Summary: In this course, students will be introduced to the processes and tools specific to Open Source Software development, and they will analyze existing projects to understand the architecture and processes of these projects. Besides, students will attempt to contribute source code to a large existing Open Source Software project. +* Course offered in 2018 and 2019. Examples of merged pull requests: [4217](https://github.com/JabRef/jabref/pull/4217), [4255](https://github.com/JabRef/jabref/pull/4255), [4227](https://github.com/JabRef/jabref/pull/4227), [4260](https://github.com/JabRef/jabref/pull/4260), [5150](https://github.com/JabRef/jabref/pull/5150) -#### Northern Arizona University (NAU), USA +#### Northern Arizona University \(NAU\), USA Course [CS499 - Open Source Software Development](https://github.com/igorsteinmacher/CS499-OSS) -- Summary: Students experience the process of getting involved in an Open Source project by engaging with a real project. Their goal is to make a "substantial" contribution to a project. -- Course offered in 2018 +* Summary: Students experience the process of getting involved in an Open Source project by engaging with a real project. Their goal is to make a "substantial" contribution to a project. +* Course offered in 2018 ### German @@ -78,29 +69,29 @@ Course [CS499 - Open Source Software Development](https://github.com/igorsteinma Course [10915-01: Software Engineering](https://dmi.unibas.ch/de/studium/computer-science-informatik/lehrangebot-hs18/vorlesung-software-engineering/) -- Lecture Materials: -- Successfully run Q3 2019. -- Excercise touching JabRef: - - General idea: identify a feature missing in JabRef and develop the specification, system design, and implementation of the feature. - - Introduction to JabRef's code: [Exercise 5](https://github.com/unibas-marcelluethi/software-engineering/blob/master/docs/week5/exercises/practical-exercises.md): Introduction into JabRef code. - - Prominent feature implemented: Parse full-text references using Grobid. PR [#5614](https://github.com/JabRef/jabref/pull/5614). +* Lecture Materials: [https://github.com/unibas-marcelluethi/software-engineering](https://github.com/unibas-marcelluethi/software-engineering) +* Successfully run Q3 2019. +* Excercise touching JabRef: + * General idea: identify a feature missing in JabRef and develop the specification, system design, and implementation of the feature. + * Introduction to JabRef's code: [Exercise 5](https://github.com/unibas-marcelluethi/software-engineering/blob/master/docs/week5/exercises/practical-exercises.md): Introduction into JabRef code. + * Prominent feature implemented: Parse full-text references using Grobid. PR [\#5614](https://github.com/JabRef/jabref/pull/5614). #### University of Stuttgart, Germany Course "Softwarepraktikum" as part of the [BSc Informatik](https://www.f05.uni-stuttgart.de/informatik/interessierte/bachelor/informatik/) -- Summary: A group of three students experienced the full software engineering process within one semester. They worked part-time for the project. -- Successfully run in 2012 +* Summary: A group of three students experienced the full software engineering process within one semester. They worked part-time for the project. +* Successfully run in 2012 Course [Studienprojekt](https://www.f05.uni-stuttgart.de/informatik/studierende/bachelor/stupro/) as part of the [BSc Software Engineering](https://www.uni-stuttgart.de/en/study/study-programs/Software-Engineering-B.Sc-00001./) -- Summary: A group of nine students experienced the full software engineering process within one year. They worked part-time for the project. -- Successfully run in 2015/2016 +* Summary: A group of nine students experienced the full software engineering process within one year. They worked part-time for the project. +* Successfully run in 2015/2016 Course "Programming and Software Development" as part of the [BSc Software Engineering](https://www.uni-stuttgart.de/en/study/study-programs/Software-Engineering-B.Sc-00001./) -- Summary: One exercise to contribute a minor fix or feature to JabRef. Goal: learn contribution to an open-source project using git and GitHub. -- Successfully run in 2018 +* Summary: One exercise to contribute a minor fix or feature to JabRef. Goal: learn contribution to an open-source project using git and GitHub. +* Successfully run in 2018 ### Swedish @@ -108,8 +99,8 @@ 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. -- Successfully run in 2020 +* 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 @@ -117,20 +108,10 @@ Course [DD2480 Software Engineering Fundamentals](https://www.kth.se/student/kur Course [Open Source Software](https://github.com/igorsteinmacher/DSL-UTFPR) -- Summary: Students are requested to contribute to an Open Source project to learn about the maintenance and evolution of software projects. This project is the predecessor of NAU's CS499. -- Course offered from 2013 to 2016 with different names - -## Interesting Read for Students and Advisors - -- [Developing Procrastination Feedback for Student Software Developers](https://medium.com/@ayaankazerouni/developing-procrastination-feedback-for-student-software-developers-1652de60db7f) by [@ayaankazerouni](https://github.com/ayaankazerouni?tab=overview&from=2015-12-01&to=2015-12-31) - > When students worked earlier and more often, they produced projects that: - > - > - were more correct, - > - were completed earlier, - > - took no more or less time to complete +* Summary: Students are requested to contribute to an Open Source project to learn about the maintenance and evolution of software projects. This project is the predecessor of NAU's CS499. +* Course offered from 2013 to 2016 with different names ## References -1: Lientz B., Swanson E., 1980: Software Maintenance Management. Addison Wesley, Reading, MA. +[1](teaching.md#a1): [@ayaankazerouni](https://github.com/ayaankazerouni): [Developing Procrastination Feedback for Student Software Developers](https://medium.com/@ayaankazerouni/developing-procrastination-feedback-for-student-software-developers-1652de60db7f) [2](teaching.md#a2): Lientz B., Swanson E., 1980: Software Maintenance Management. Addison Wesley, Reading, MA. - diff --git a/mlc_config.json b/mlc_config.json new file mode 100644 index 00000000000..91ac75cfd09 --- /dev/null +++ b/mlc_config.json @@ -0,0 +1,25 @@ +{ + "ignorePatterns": [ + { + "pattern": "^CONTRIBUTING\\.md" + }, + { + "pattern": "^https://dl\\.acm\\.org" + }, + { + "pattern": "^https://github\\.com" + }, + { + "pattern": "^https://.*\\.jabref\\.org" + }, + { + "pattern": "^https://sourcespy\\.com/.*" + }, + { + "pattern": "^http://purl\\.org/net/bibteXMP" + }, + { + "pattern": "^http://localhost" + } + ] +} diff --git a/settings.gradle b/settings.gradle index ee77a0edcfa..f6a8d740984 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,10 @@ +pluginManagement { + repositories { + maven { + url 'https://oss.sonatype.org/content/repositories/snapshots' + } + gradlePluginPortal() + } +} + rootProject.name = "JabRef" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 60ac1a3d445..e2f6f98f205 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -3,7 +3,11 @@ adopt-info: jabref icon: snap/gui/jabref.png license: MIT summary: Bibliography manager -description: JabRef is an open source bibliography reference manager. The native file format used by JabRef is BibTeX, the standard LaTeX bibliography format. +description: | + JabRef is an open source bibliography reference manager. + The native file format used by JabRef is BibTeX, the standard LaTeX bibliography format. + To access files in external media (i.e. usb drives) you must run: + `snap connect jabref:removable-media` grade: stable confinement: strict diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index cef5e7d6656..721f6a686fd 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -104,6 +104,13 @@ private void openWindow(Stage mainStage) { } }); Platform.runLater(this::openDatabases); + + if (!(Globals.getFileUpdateMonitor().isActive())) { + this.getMainFrame().getDialogService() + .showErrorDialogAndWait(Localization.lang("Unable to monitor file changes. Please close files " + + "and processes and restart. You may encounter errors if you continue " + + "with this session.")); + } } private void openDatabases() { diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index 957a0fab500..ed312c8a7d8 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -16,7 +16,7 @@ import org.jabref.gui.externalfiles.AutoSetFileLinksUtil; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.undo.NamedCompound; -import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; +import org.jabref.logic.citationkeypattern.CitationKeyGenerator; import org.jabref.logic.exporter.AtomicFileWriter; import org.jabref.logic.exporter.BibDatabaseWriter; import org.jabref.logic.exporter.BibtexDatabaseWriter; @@ -206,8 +206,8 @@ private List processArguments() { } } - if (cli.isGenerateBibtexKeys()) { - regenerateBibtexKeys(loaded); + if (cli.isGenerateCitationKeys()) { + regenerateCitationKeys(loaded); } if (cli.isAutomaticallySetFileLinks()) { @@ -500,13 +500,13 @@ private void automaticallySetFileLinks(List loaded) { } } - private void regenerateBibtexKeys(List loaded) { + private void regenerateCitationKeys(List loaded) { for (ParserResult parserResult : loaded) { BibDatabase database = parserResult.getDatabase(); - LOGGER.info(Localization.lang("Regenerating BibTeX keys according to metadata")); + LOGGER.info(Localization.lang("Regenerating citation keys according to metadata")); - BibtexKeyGenerator keyGenerator = new BibtexKeyGenerator(parserResult.getDatabaseContext(), Globals.prefs.getBibtexKeyPatternPreferences()); + CitationKeyGenerator keyGenerator = new CitationKeyGenerator(parserResult.getDatabaseContext(), Globals.prefs.getCitationKeyPatternPreferences()); for (BibEntry entry : database.getEntries()) { keyGenerator.generateAndSetKey(entry); } diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index 167875b322d..f9b0b4d4cbf 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -139,8 +139,8 @@ public String getExportMatches() { return cl.getOptionValue("exportMatches"); } - public boolean isGenerateBibtexKeys() { - return cl.hasOption("generateBibtexKeys"); + public boolean isGenerateCitationKeys() { + return cl.hasOption("generateCitationKeys"); } public boolean isAutomaticallySetFileLinks() { @@ -154,7 +154,7 @@ private static Options getOptions() { options.addOption("h", "help", false, Localization.lang("Display help on command line options")); options.addOption("n", "nogui", false, Localization.lang("No GUI. Only process command line options")); options.addOption("asfl", "automaticallySetFileLinks", false, Localization.lang("Automatically set file links")); - options.addOption("g", "generateBibtexKeys", false, Localization.lang("Regenerate all keys for the entries in a BibTeX file")); + options.addOption("g", "generateCitationKeys", false, Localization.lang("Regenerate all keys for the entries in a BibTeX file")); options.addOption("b", "blank", false, Localization.lang("Do not open any files at startup")); options.addOption("v", "version", false, Localization.lang("Display version")); options.addOption(null, "debug", false, Localization.lang("Show debug level messages")); diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index a6b527cde4d..c0140fbd8b6 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -101,7 +101,7 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas bibDatabaseContext.getMetaData().registerListener(this); this.sidePaneManager = frame.getSidePaneManager(); - this.tableModel = new MainTableDataModel(getBibDatabaseContext()); + this.tableModel = new MainTableDataModel(getBibDatabaseContext(), Globals.prefs, Globals.stateManager); citationStyleCache = new CitationStyleCache(bibDatabaseContext); annotationCache = new FileAnnotationCache(bibDatabaseContext, Globals.prefs.getFilePreferences()); diff --git a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java index 8b658a1655e..4ab27396efa 100644 --- a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java +++ b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java @@ -11,6 +11,7 @@ */ public class DragAndDropDataFormats { + public static final DataFormat FIELD = new DataFormat("dnd/org.jabref.model.entry.field.Field"); public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode"); public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile"); public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries"); diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index 658730b7f1c..fc3fbfb1d65 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -119,7 +119,7 @@ private void addEntriesToPane(FlowPane pane, Collection @FXML public void initialize() { visualizer.setDecoration(new IconValidationDecorator()); - viewModel = new EntryTypeViewModel(prefs, basePanel, dialogService); + viewModel = new EntryTypeViewModel(prefs, basePanel, dialogService, stateManager); idBasedFetchers.itemsProperty().bind(viewModel.fetcherItemsProperty()); idTextField.textProperty().bindBidirectional(viewModel.idTextProperty()); diff --git a/src/main/java/org/jabref/gui/EntryTypeViewModel.java b/src/main/java/org/jabref/gui/EntryTypeViewModel.java index 5d24dde230a..2326c66cf7e 100644 --- a/src/main/java/org/jabref/gui/EntryTypeViewModel.java +++ b/src/main/java/org/jabref/gui/EntryTypeViewModel.java @@ -17,7 +17,7 @@ import org.jabref.Globals; import org.jabref.gui.duplicationFinder.DuplicateResolverDialog; import org.jabref.logic.bibtex.DuplicateCheck; -import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; +import org.jabref.logic.citationkeypattern.CitationKeyGenerator; import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.IdBasedFetcher; import org.jabref.logic.importer.WebFetchers; @@ -49,11 +49,13 @@ public class EntryTypeViewModel { private final BasePanel basePanel; private final DialogService dialogService; private final Validator idFieldValidator; + private final StateManager stateManager; - public EntryTypeViewModel(JabRefPreferences preferences, BasePanel basePanel, DialogService dialogService) { + public EntryTypeViewModel(JabRefPreferences preferences, BasePanel basePanel, DialogService dialogService, StateManager stateManager) { this.basePanel = basePanel; this.prefs = preferences; this.dialogService = dialogService; + this.stateManager = stateManager; fetchers.addAll(WebFetchers.getIdBasedFetchers(preferences.getImportFormatPreferences())); selectedItemProperty.setValue(getLastSelectedFetcher()); idFieldValidator = new FunctionBasedValidator<>(idText, StringUtil::isNotBlank, ValidationMessage.error(Localization.lang("Required field \"%0\" is empty.", Localization.lang("ID")))); @@ -147,7 +149,7 @@ public void runFetcherWorker() { final BibEntry entry = result.get(); Optional duplicate = new DuplicateCheck(Globals.entryTypesManager).containsDuplicate(basePanel.getDatabase(), entry, basePanel.getBibDatabaseContext().getMode()); if ((duplicate.isPresent())) { - DuplicateResolverDialog dialog = new DuplicateResolverDialog(entry, duplicate.get(), DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, basePanel.getBibDatabaseContext()); + DuplicateResolverDialog dialog = new DuplicateResolverDialog(entry, duplicate.get(), DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, basePanel.getBibDatabaseContext(), stateManager); switch (dialog.showAndWait().orElse(DuplicateResolverDialog.DuplicateResolverResult.BREAK)) { case KEEP_LEFT: basePanel.getDatabase().removeEntry(duplicate.get()); @@ -166,7 +168,7 @@ public void runFetcherWorker() { } } else { // Regenerate CiteKey of imported BibEntry - new BibtexKeyGenerator(basePanel.getBibDatabaseContext(), prefs.getBibtexKeyPatternPreferences()).generateAndSetKey(entry); + new CitationKeyGenerator(basePanel.getBibDatabaseContext(), prefs.getCitationKeyPatternPreferences()).generateAndSetKey(entry); basePanel.insertEntry(entry); } searchSuccesfulProperty.set(true); diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 68938bb91c4..ebaa8f7df41 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -1,6 +1,7 @@ package org.jabref.gui; import java.io.File; +import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -48,17 +49,19 @@ import org.jabref.Globals; import org.jabref.JabRefExecutorService; import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.actions.StandardActions; import org.jabref.gui.auximport.NewSubLibraryAction; import org.jabref.gui.bibtexextractor.ExtractBibtexAction; -import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternAction; -import org.jabref.gui.bibtexkeypattern.GenerateBibtexKeyAction; +import org.jabref.gui.citationkeypattern.CitationKeyPatternAction; +import org.jabref.gui.citationkeypattern.GenerateCitationKeyAction; import org.jabref.gui.cleanup.CleanupAction; import org.jabref.gui.contentselector.ManageContentSelectorAction; import org.jabref.gui.copyfiles.CopyFilesAction; import org.jabref.gui.customentrytypes.CustomizeEntryAction; import org.jabref.gui.customizefields.SetupGeneralFieldsAction; +import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.dialogs.AutosaveUiManager; import org.jabref.gui.documentviewer.ShowDocumentViewerAction; import org.jabref.gui.duplicationFinder.DuplicateSearch; @@ -173,6 +176,7 @@ public class JabRefFrame extends BorderPane { private SidePaneManager sidePaneManager; private TabPane tabbedPane; private SidePane sidePane; + private PopOver progressViewPopOver; public JabRefFrame(Stage mainStage) { this.mainStage = mainStage; @@ -182,6 +186,13 @@ public JabRefFrame(Stage mainStage) { this.undoManager = Globals.undoManager; this.fileHistory = new FileHistoryMenu(prefs, dialogService, getOpenDatabaseAction()); this.executorService = JabRefExecutorService.INSTANCE; + this.setOnKeyTyped(key -> { + if (this.fileHistory.isShowing()) { + if (this.fileHistory.openFileByKey(key)) { + this.fileHistory.getParentMenu().hide(); + } + } + }); } private static BasePanel getBasePanel(Tab tab) { @@ -530,7 +541,7 @@ private Node createToolbar() { factory.createIconButton(StandardActions.PASTE, new EditAction(StandardActions.PASTE, this, stateManager)), new Separator(Orientation.VERTICAL), pushToApplicationButton, - factory.createIconButton(StandardActions.GENERATE_CITE_KEYS, new GenerateBibtexKeyAction(this, dialogService, stateManager)), + factory.createIconButton(StandardActions.GENERATE_CITE_KEYS, new GenerateCitationKeyAction(this, dialogService, stateManager)), factory.createIconButton(StandardActions.CLEANUP_ENTRIES, new CleanupAction(this, prefs, dialogService, stateManager)), new Separator(Orientation.VERTICAL), factory.createIconButton(StandardActions.OPEN_GITHUB, new OpenBrowserAction("https://github.com/JabRef/jabref")), @@ -763,7 +774,7 @@ private MenuBar createMenu() { new SeparatorMenuItem(), factory.createMenuItem(StandardActions.REPLACE_ALL, new ReplaceStringAction(this, stateManager)), - factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new GenerateBibtexKeyAction(this, dialogService, stateManager)), + factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new GenerateCitationKeyAction(this, dialogService, stateManager)), new SeparatorMenuItem(), @@ -796,7 +807,7 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.LIBRARY_PROPERTIES, new LibraryPropertiesAction(this, stateManager)), factory.createMenuItem(StandardActions.EDIT_PREAMBLE, new PreambleEditor(stateManager, undoManager, this.getDialogService())), factory.createMenuItem(StandardActions.EDIT_STRINGS, new BibtexStringEditorAction(stateManager)), - factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new BibtexKeyPatternAction(this, stateManager)) + factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new CitationKeyPatternAction(this, stateManager)) ); quality.getItems().addAll( @@ -982,11 +993,18 @@ hide it and clip it to a square of (width x width) each time width is updated. taskProgressView.setRetainTasks(true); taskProgressView.setGraphicFactory(BackgroundTask::getIcon); - PopOver progressViewPopOver = new PopOver(taskProgressView); - progressViewPopOver.setTitle(Localization.lang("Background Tasks")); - progressViewPopOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_TOP); - - progressViewPopOver.show(indicator); + if (progressViewPopOver == null) { + progressViewPopOver = new PopOver(taskProgressView); + progressViewPopOver.setTitle(Localization.lang("Background Tasks")); + progressViewPopOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_TOP); + progressViewPopOver.setContentNode(taskProgressView); + progressViewPopOver.show(indicator); + } else if (progressViewPopOver.isShowing()) { + progressViewPopOver.hide(); + } else { + progressViewPopOver.setContentNode(taskProgressView); + progressViewPopOver.show(indicator); + } }); return new Group(indicator); @@ -1079,11 +1097,18 @@ public void updateAllTabTitles() { } } - private static ContextMenu createTabContextMenu(KeyBindingRepository keyBindingRepository, BasePanel panel, StateManager stateManager) { + private ContextMenu createTabContextMenu(KeyBindingRepository keyBindingRepository) { ContextMenu contextMenu = new ContextMenu(); ActionFactory factory = new ActionFactory(keyBindingRepository); - contextMenu.getItems().add(factory.createMenuItem(StandardActions.LIBRARY_PROPERTIES, new LibraryPropertiesAction(panel.frame(), stateManager))); + contextMenu.getItems().addAll( + factory.createMenuItem(StandardActions.CLOSE_LIBRARY, new CloseDatabaseAction()), + factory.createMenuItem(StandardActions.CLOSE_OTHER_LIBRARIES, new CloseOthersDatabaseAction()), + factory.createMenuItem(StandardActions.CLOSE_ALL_LIBRARIES, new CloseAllDatabaseAction()), + new SeparatorMenuItem(), + factory.createMenuItem(StandardActions.OPEN_DATABASE_FOLDER, new OpenDatabaseFolder()), + factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OpenConsoleAction(stateManager)) + ); return contextMenu; } @@ -1098,7 +1123,7 @@ public void addTab(BasePanel basePanel, boolean raisePanel) { }); // add tab context menu - newTab.setContextMenu(createTabContextMenu(Globals.getKeyPrefs(), basePanel, stateManager)); + newTab.setContextMenu(createTabContextMenu(Globals.getKeyPrefs())); // update all tab titles updateAllTabTitles(); @@ -1316,6 +1341,49 @@ public void execute() { } } + private class CloseOthersDatabaseAction extends SimpleCommand { + + public CloseOthersDatabaseAction() { + this.executable.bind(ActionHelper.isOpenMultiDatabase(tabbedPane)); + } + + @Override + public void execute() { + BasePanel currentBasePanel = getCurrentBasePanel(); + for (Tab tab : tabbedPane.getTabs()) { + BasePanel basePanel = getBasePanel(tab); + if (basePanel != currentBasePanel) { + closeTab(basePanel); + } + } + } + } + + private class CloseAllDatabaseAction extends SimpleCommand { + + @Override + public void execute() { + for (Tab tab : tabbedPane.getTabs()) { + BasePanel basePanel = getBasePanel(tab); + closeTab(basePanel); + } + } + } + + private class OpenDatabaseFolder extends SimpleCommand { + + @Override + public void execute() { + stateManager.getActiveDatabase().flatMap(BibDatabaseContext::getDatabasePath).ifPresent(path -> { + try { + JabRefDesktop.openFolderAndSelectFile(path); + } catch (IOException e) { + LOGGER.info("Could not open folder", e); + } + }); + } + } + private class UndoRedoEventManager { @Subscribe diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index 8509adc5928..7554467b7ed 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -18,6 +18,7 @@ import javafx.scene.Node; import org.jabref.gui.util.CustomLocalDragboard; +import org.jabref.gui.util.DialogWindowState; import org.jabref.gui.util.OptionalObjectProperty; import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabaseContext; @@ -37,6 +38,7 @@ *
  • active search
  • *
  • active number of search results
  • *
  • focus owner
  • + *
  • dialog window sizes/positions
  • * */ public class StateManager { @@ -52,10 +54,9 @@ public class StateManager { private final ObservableList> backgroundTasks = FXCollections.observableArrayList(task -> { return new Observable[]{task.progressProperty(), task.runningProperty()}; }); - private final EasyBinding anyTaskRunning = EasyBind.reduce(backgroundTasks, tasks -> tasks.anyMatch(Task::isRunning)); - private final EasyBinding tasksProgress = EasyBind.reduce(backgroundTasks, tasks -> tasks.filter(Task::isRunning).mapToDouble(Task::getProgress).average().orElse(1)); + private final ObservableMap dialogWindowStates = FXCollections.observableHashMap(); public StateManager() { activeGroups.bind(Bindings.valueAt(selectedGroups, activeDatabase.orElse(null))); @@ -147,4 +148,12 @@ public EasyBinding getAnyTaskRunning() { public EasyBinding getTasksProgress() { return tasksProgress; } + + public DialogWindowState getDialogWindowState(String className) { + return dialogWindowStates.get(className); + } + + public void setDialogWindowState(String className, DialogWindowState state) { + dialogWindowStates.put(className, state); + } } diff --git a/src/main/java/org/jabref/gui/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java index d0b75659396..9174d96ff82 100644 --- a/src/main/java/org/jabref/gui/actions/ActionFactory.java +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -1,5 +1,6 @@ package org.jabref.gui.actions; +import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Objects; @@ -66,7 +67,7 @@ private static Label getAssociatedNode(MenuItem menuItem) { Method getLabel = ContextMenuContent.MenuItemContainer.class.getDeclaredMethod("getLabel"); getLabel.setAccessible(true); return (Label) getLabel.invoke(container); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + } catch (InaccessibleObjectException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { LOGGER.warn("Could not get label of menu item", e); } } @@ -139,6 +140,7 @@ public Button createIconButton(Action action, Command command) { } public ButtonBase configureIconButton(Action action, Command command, ButtonBase button) { + ActionUtils.unconfigureButton(button); ActionUtils.configureButton( new JabRefAction(action, command, keyBindingRepository, Sources.FromButton), button, diff --git a/src/main/java/org/jabref/gui/actions/ActionHelper.java b/src/main/java/org/jabref/gui/actions/ActionHelper.java index dfad438f8c0..acda7c7c1df 100644 --- a/src/main/java/org/jabref/gui/actions/ActionHelper.java +++ b/src/main/java/org/jabref/gui/actions/ActionHelper.java @@ -9,6 +9,7 @@ import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanExpression; import javafx.collections.ObservableList; +import javafx.scene.control.TabPane; import org.jabref.gui.StateManager; import org.jabref.model.entry.BibEntry; @@ -72,4 +73,8 @@ public static BooleanExpression isFilePresentForSelectedEntry(StateManager state return BooleanExpression.booleanExpression(fileIsPresent); } + + public static BooleanExpression isOpenMultiDatabase(TabPane tabbedPane) { + return Bindings.size(tabbedPane.getTabs()).greaterThan(1); + } } diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index df87f1b7e04..31c848def09 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -12,10 +12,10 @@ public enum StandardActions implements Action { COPY_MORE(Localization.lang("Copy") + "..."), COPY_TITLE(Localization.lang("Copy title"), KeyBinding.COPY_TITLE), - COPY_KEY(Localization.lang("Copy BibTeX key"), KeyBinding.COPY_BIBTEX_KEY), - COPY_CITE_KEY(Localization.lang("Copy \\cite{BibTeX key}"), KeyBinding.COPY_CITE_BIBTEX_KEY), - COPY_KEY_AND_TITLE(Localization.lang("Copy BibTeX key and title"), KeyBinding.COPY_BIBTEX_KEY_AND_TITLE), - COPY_KEY_AND_LINK(Localization.lang("Copy BibTeX key and link"), KeyBinding.COPY_BIBTEX_KEY_AND_LINK), + COPY_KEY(Localization.lang("Copy citation key"), KeyBinding.COPY_CITATION_KEY), + COPY_CITE_KEY(Localization.lang("Copy \\cite{citation key}"), KeyBinding.COPY_CITE_CITATION_KEY), + COPY_KEY_AND_TITLE(Localization.lang("Copy citation key and title"), KeyBinding.COPY_CITATION_KEY_AND_TITLE), + COPY_KEY_AND_LINK(Localization.lang("Copy citation key and link"), KeyBinding.COPY_CITATION_KEY_AND_LINK), COPY_CITATION_HTML(Localization.lang("Copy citation") + " (HTML)", KeyBinding.COPY_PREVIEW), COPY_CITATION_MORE(Localization.lang("Copy citation") + "..."), COPY_CITATION_TEXT("Text"), @@ -75,7 +75,9 @@ public enum StandardActions implements Action { EXPORT_SELECTED(Localization.lang("Export selected entries"), KeyBinding.EXPORT_SELECTED), CONNECT_TO_SHARED_DB(Localization.lang("Connect to shared database"), IconTheme.JabRefIcons.CONNECT_DB), PULL_CHANGES_FROM_SHARED_DB(Localization.lang("Pull changes from shared database"), KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), - CLOSE_LIBRARY(Localization.lang("Close library"), Localization.lang("Close the current library"), IconTheme.JabRefIcons.CLOSE, KeyBinding.CLOSE_DATABASE), + CLOSE_LIBRARY(Localization.lang("Close"), Localization.lang("Close the current library"), IconTheme.JabRefIcons.CLOSE, KeyBinding.CLOSE_DATABASE), + CLOSE_OTHER_LIBRARIES(Localization.lang("Close others"), Localization.lang("Close other libraries"), IconTheme.JabRefIcons.CLOSE), + CLOSE_ALL_LIBRARIES(Localization.lang("Close all"), Localization.lang("Close all libraries"), IconTheme.JabRefIcons.CLOSE), QUIT(Localization.lang("Quit"), Localization.lang("Quit JabRef"), IconTheme.JabRefIcons.CLOSE_JABREF, KeyBinding.QUIT_JABREF), UNDO(Localization.lang("Undo"), IconTheme.JabRefIcons.UNDO, KeyBinding.UNDO), REDO(Localization.lang("Redo"), IconTheme.JabRefIcons.REDO, KeyBinding.REDO), @@ -89,6 +91,7 @@ public enum StandardActions implements Action { PARSE_LATEX(Localization.lang("Search for citations in LaTeX files..."), IconTheme.JabRefIcons.LATEX_CITATIONS), NEW_SUB_LIBRARY_FROM_AUX(Localization.lang("New sublibrary based on AUX file") + "...", Localization.lang("New BibTeX sublibrary") + Localization.lang("This feature generates a new library based on which entries are needed in an existing LaTeX document."), IconTheme.JabRefIcons.NEW), WRITE_XMP(Localization.lang("Write XMP metadata to PDFs"), Localization.lang("Will write XMP metadata to the PDFs linked from selected entries."), KeyBinding.WRITE_XMP), + OPEN_DATABASE_FOLDER(Localization.lang("Reveal in file explorer")), OPEN_FOLDER(Localization.lang("Open folder"), Localization.lang("Open folder"), KeyBinding.OPEN_FOLDER), OPEN_FILE(Localization.lang("Open file"), Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), OPEN_CONSOLE(Localization.lang("Open terminal here"), Localization.lang("Open terminal here"), IconTheme.JabRefIcons.CONSOLE, KeyBinding.OPEN_CONSOLE), @@ -106,12 +109,12 @@ public enum StandardActions implements Action { SETUP_GENERAL_FIELDS(Localization.lang("Set up general fields")), MANAGE_EXTERNAL_FILETYPES(Localization.lang("Manage external file types")), MANAGE_PROTECTED_TERMS(Localization.lang("Manage protected terms")), - BIBTEX_KEY_PATTERN(Localization.lang("BibTeX key patterns")), + CITATION_KEY_PATTERN(Localization.lang("Citation key patterns")), SHOW_PREFS(Localization.lang("Preferences")), MANAGE_JOURNALS(Localization.lang("Manage journal abbreviations")), CUSTOMIZE_KEYBINDING(Localization.lang("Customize key bindings"), IconTheme.JabRefIcons.KEY_BINDINGS), MANAGE_CONTENT_SELECTORS(Localization.lang("Manage content selectors"), IconTheme.JabRefIcons.PREFERENCES), - MANAGE_CITE_KEY_PATTERNS(Localization.lang("BibTeX key patterns")), + MANAGE_CITE_KEY_PATTERNS(Localization.lang("Citation key patterns")), EDIT_ENTRY(Localization.lang("Open entry editor"), IconTheme.JabRefIcons.EDIT_ENTRY, KeyBinding.EDIT_ENTRY), SHOW_PDF_VIEWER(Localization.lang("Open document viewer"), IconTheme.JabRefIcons.PDF_FILE), @@ -128,14 +131,14 @@ public enum StandardActions implements Action { FIND_DUPLICATES(Localization.lang("Find duplicates"), IconTheme.JabRefIcons.FIND_DUPLICATES), MERGE_ENTRIES(Localization.lang("Merge entries"), IconTheme.JabRefIcons.MERGE_ENTRIES), - RESOLVE_DUPLICATE_KEYS(Localization.lang("Resolve duplicate BibTeX keys"), Localization.lang("Find and remove duplicate BibTeX keys"), KeyBinding.RESOLVE_DUPLICATE_BIBTEX_KEYS), + RESOLVE_DUPLICATE_KEYS(Localization.lang("Resolve duplicate citation keys"), Localization.lang("Find and remove duplicate citation keys"), KeyBinding.RESOLVE_DUPLICATE_CITATION_KEYS), CHECK_INTEGRITY(Localization.lang("Check integrity"), KeyBinding.CHECK_INTEGRITY), FIND_UNLINKED_FILES(Localization.lang("Search for unlinked local files"), IconTheme.JabRefIcons.SEARCH, KeyBinding.FIND_UNLINKED_FILES), AUTO_LINK_FILES(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), LOOKUP_DOC_IDENTIFIER(Localization.lang("Search document identifier online")), LOOKUP_FULLTEXT(Localization.lang("Search full text documents online"), IconTheme.JabRefIcons.FILE_SEARCH, KeyBinding.DOWNLOAD_FULL_TEXT), - GENERATE_CITE_KEY(Localization.lang("Generate BibTeX key"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - GENERATE_CITE_KEYS(Localization.lang("Generate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), + GENERATE_CITE_KEY(Localization.lang("Generate citation key"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_CITATION_KEYS), + GENERATE_CITE_KEYS(Localization.lang("Generate citation keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_CITATION_KEYS), DOWNLOAD_FULL_TEXT(Localization.lang("Search full text documents online"), IconTheme.JabRefIcons.FILE_SEARCH, KeyBinding.DOWNLOAD_FULL_TEXT), CLEANUP_ENTRIES(Localization.lang("Cleanup entries"), IconTheme.JabRefIcons.CLEANUP_ENTRIES, KeyBinding.CLEANUP), SET_FILE_LINKS(Localization.lang("Automatically set file links"), KeyBinding.AUTOMATICALLY_LINK_FILES), diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternAction.java b/src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternAction.java similarity index 57% rename from src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternAction.java rename to src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternAction.java index 6875e350836..74f20a3b7b4 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternAction.java +++ b/src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternAction.java @@ -1,4 +1,4 @@ -package org.jabref.gui.bibtexkeypattern; +package org.jabref.gui.citationkeypattern; import org.jabref.gui.JabRefFrame; import org.jabref.gui.StateManager; @@ -6,11 +6,11 @@ import static org.jabref.gui.actions.ActionHelper.needsDatabase; -public class BibtexKeyPatternAction extends SimpleCommand { +public class CitationKeyPatternAction extends SimpleCommand { private final JabRefFrame frame; - public BibtexKeyPatternAction(JabRefFrame frame, StateManager stateManager) { + public CitationKeyPatternAction(JabRefFrame frame, StateManager stateManager) { this.frame = frame; this.executable.bind(needsDatabase(stateManager)); @@ -18,6 +18,6 @@ public BibtexKeyPatternAction(JabRefFrame frame, StateManager stateManager) { @Override public void execute() { - new BibtexKeyPatternDialog(frame.getCurrentBasePanel()).showAndWait(); + new CitationKeyPatternDialog(frame.getCurrentBasePanel()).showAndWait(); } } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java b/src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternDialog.java similarity index 67% rename from src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java rename to src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternDialog.java index fcafab1638e..e051ff2dcbb 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java +++ b/src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternDialog.java @@ -1,4 +1,4 @@ -package org.jabref.gui.bibtexkeypattern; +package org.jabref.gui.citationkeypattern; import javafx.scene.control.ButtonType; @@ -6,34 +6,34 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.util.BaseDialog; import org.jabref.logic.l10n.Localization; -import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; +import org.jabref.model.bibtexkeypattern.AbstractCitationKeyPattern; import org.jabref.model.metadata.MetaData; -public class BibtexKeyPatternDialog extends BaseDialog { +public class CitationKeyPatternDialog extends BaseDialog { private final MetaData metaData; private final BasePanel panel; - private final BibtexKeyPatternPanel bibtexKeyPatternPanel; + private final CitationKeyPatternPanel citationKeyPatternPanel; - public BibtexKeyPatternDialog(BasePanel panel) { - this.bibtexKeyPatternPanel = new BibtexKeyPatternPanel(panel); + public CitationKeyPatternDialog(BasePanel panel) { + this.citationKeyPatternPanel = new CitationKeyPatternPanel(panel); this.panel = panel; this.metaData = panel.getBibDatabaseContext().getMetaData(); - AbstractBibtexKeyPattern keyPattern = metaData.getCiteKeyPattern(Globals.prefs.getGlobalBibtexKeyPattern()); - bibtexKeyPatternPanel.setValues(keyPattern); + AbstractCitationKeyPattern keyPattern = metaData.getCiteKeyPattern(Globals.prefs.getGlobalCitationKeyPattern()); + citationKeyPatternPanel.setValues(keyPattern); init(); } private void init() { - this.setTitle(Localization.lang("BibTeX key patterns")); + this.setTitle(Localization.lang("Citation key patterns")); - this.getDialogPane().setContent(bibtexKeyPatternPanel.getPanel()); + this.getDialogPane().setContent(citationKeyPatternPanel.getPanel()); this.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.CANCEL); this.setResultConverter(button -> { if (button == ButtonType.APPLY) { - metaData.setCiteKeyPattern(bibtexKeyPatternPanel.getKeyPatternAsDatabaseBibtexKeyPattern()); + metaData.setCiteKeyPattern(citationKeyPatternPanel.getKeyPatternAsDatabaseKeyPattern()); panel.markNonUndoableBaseChanged(); } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternPanel.java similarity index 82% rename from src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java rename to src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternPanel.java index 3d5356e5ef5..c9114dc89dd 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/citationkeypattern/CitationKeyPatternPanel.java @@ -1,4 +1,4 @@ -package org.jabref.gui.bibtexkeypattern; +package org.jabref.gui.citationkeypattern; import java.util.HashMap; import java.util.Map; @@ -17,14 +17,14 @@ import org.jabref.gui.help.HelpAction; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; -import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; -import org.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern; +import org.jabref.model.bibtexkeypattern.AbstractCitationKeyPattern; +import org.jabref.model.bibtexkeypattern.DatabaseCitationKeyPattern; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.types.EntryType; import org.jabref.preferences.JabRefPreferences; -public class BibtexKeyPatternPanel extends Pane { +public class CitationKeyPatternPanel extends Pane { // default pattern protected final TextField defaultPat = new TextField(); @@ -34,14 +34,14 @@ public class BibtexKeyPatternPanel extends Pane { private final BasePanel panel; private final GridPane gridPane = new GridPane(); - public BibtexKeyPatternPanel(BasePanel panel) { + public CitationKeyPatternPanel(BasePanel panel) { this.panel = panel; gridPane.setHgap(10); gridPane.setVgap(5); buildGUI(); } - private static void setValue(TextField tf, EntryType fieldName, AbstractBibtexKeyPattern keyPattern) { + private static void setValue(TextField tf, EntryType fieldName, AbstractCitationKeyPattern keyPattern) { if (keyPattern.isDefaultValue(fieldName)) { tf.setText(""); } else { @@ -74,7 +74,7 @@ private void buildGUI() { rowIndex++; Label defaultPattern = new Label(Localization.lang("Default pattern")); Button button = new Button("Default"); - button.setOnAction(e -> defaultPat.setText((String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN))); + button.setOnAction(e -> defaultPat.setText((String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_CITATION_KEY_PATTERN))); gridPane.add(defaultPattern, 1, rowIndex); gridPane.add(defaultPat, 2, rowIndex); gridPane.add(button, 3, rowIndex); @@ -84,7 +84,7 @@ private void buildGUI() { Label label1 = new Label(type.getType().getDisplayName()); TextField textField = new TextField(); Button button1 = new Button("Default"); - button1.setOnAction(e1 -> textField.setText((String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN))); + button1.setOnAction(e1 -> textField.setText((String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_CITATION_KEY_PATTERN))); gridPane.add(label1, 1 + (columnIndex * 3), rowIndex); gridPane.add(textField, 2 + (columnIndex * 3), rowIndex); @@ -103,7 +103,7 @@ private void buildGUI() { rowIndex++; ActionFactory factory = new ActionFactory(Globals.prefs.getKeyBindingRepository()); - Button help = factory.createIconButton(StandardActions.HELP_KEY_PATTERNS, new HelpAction(HelpFile.BIBTEX_KEY_PATTERN)); + Button help = factory.createIconButton(StandardActions.HELP_KEY_PATTERNS, new HelpAction(HelpFile.CITATION_KEY_PATTERN)); gridPane.add(help, 1, rowIndex); Button btnDefaultAll1 = new Button(Localization.lang("Reset all")); @@ -112,13 +112,13 @@ private void buildGUI() { for (TextField field : textFields.values()) { field.setText(""); } - defaultPat.setText((String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + defaultPat.setText((String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_CITATION_KEY_PATTERN)); }); gridPane.add(btnDefaultAll1, 2, rowIndex); } - public DatabaseBibtexKeyPattern getKeyPatternAsDatabaseBibtexKeyPattern() { - DatabaseBibtexKeyPattern res = new DatabaseBibtexKeyPattern(Globals.prefs.getGlobalBibtexKeyPattern()); + public DatabaseCitationKeyPattern getKeyPatternAsDatabaseKeyPattern() { + DatabaseCitationKeyPattern res = new DatabaseCitationKeyPattern(Globals.prefs.getGlobalCitationKeyPattern()); fillPatternUsingPanelData(res); return res; } @@ -126,12 +126,12 @@ public DatabaseBibtexKeyPattern getKeyPatternAsDatabaseBibtexKeyPattern() { /** * fill the given LabelPattern by values generated from the text fields */ - private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { + private void fillPatternUsingPanelData(AbstractCitationKeyPattern keypatterns) { // each entry type for (Map.Entry entry : textFields.entrySet()) { String text = entry.getValue().getText(); if (!text.trim().isEmpty()) { - keypatterns.addBibtexKeyPattern(entry.getKey(), text); + keypatterns.addCitationKeyPattern(entry.getKey(), text); } } @@ -145,9 +145,9 @@ private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { /** * Fills the current values to the text fields * - * @param keyPattern the BibtexKeyPattern to use as initial value + * @param keyPattern the CitationKeyPattern to use as initial value */ - public void setValues(AbstractBibtexKeyPattern keyPattern) { + public void setValues(AbstractCitationKeyPattern keyPattern) { for (Map.Entry entry : textFields.entrySet()) { setValue(entry.getValue(), entry.getKey(), keyPattern); } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java b/src/main/java/org/jabref/gui/citationkeypattern/GenerateCitationKeyAction.java similarity index 86% rename from src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java rename to src/main/java/org/jabref/gui/citationkeypattern/GenerateCitationKeyAction.java index 246d672650d..208d8216a15 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java +++ b/src/main/java/org/jabref/gui/citationkeypattern/GenerateCitationKeyAction.java @@ -1,4 +1,4 @@ -package org.jabref.gui.bibtexkeypattern; +package org.jabref.gui.citationkeypattern; import java.util.List; @@ -11,12 +11,12 @@ import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableKeyChange; import org.jabref.gui.util.BackgroundTask; -import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; +import org.jabref.logic.citationkeypattern.CitationKeyGenerator; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; -public class GenerateBibtexKeyAction extends SimpleCommand { +public class GenerateCitationKeyAction extends SimpleCommand { private final JabRefFrame frame; private final DialogService dialogService; @@ -25,7 +25,7 @@ public class GenerateBibtexKeyAction extends SimpleCommand { private List entries; private boolean isCanceled; - public GenerateBibtexKeyAction(JabRefFrame frame, DialogService dialogService, StateManager stateManager) { + public GenerateCitationKeyAction(JabRefFrame frame, DialogService dialogService, StateManager stateManager) { this.frame = frame; this.dialogService = dialogService; this.stateManager = stateManager; @@ -38,11 +38,11 @@ public void execute() { entries = stateManager.getSelectedEntries(); if (entries.isEmpty()) { - dialogService.showWarningDialogAndWait(Localization.lang("Autogenerate BibTeX keys"), + dialogService.showWarningDialogAndWait(Localization.lang("Autogenerate citation keys"), Localization.lang("First select the entries you want keys to be generated for.")); return; } - dialogService.notify(formatOutputMessage(Localization.lang("Generating BibTeX key for"), entries.size())); + dialogService.notify(formatOutputMessage(Localization.lang("Generating citation key for"), entries.size())); checkOverwriteKeysChosen(); @@ -88,8 +88,9 @@ private void generateKeys() { stateManager.getActiveDatabase().ifPresent(databaseContext -> { // generate the new cite keys for each entry - final NamedCompound compound = new NamedCompound(Localization.lang("Autogenerate BibTeX keys")); - BibtexKeyGenerator keyGenerator = new BibtexKeyGenerator(databaseContext, Globals.prefs.getBibtexKeyPatternPreferences()); + final NamedCompound compound = new NamedCompound(Localization.lang("Autogenerate citation keys")); + CitationKeyGenerator keyGenerator = + new CitationKeyGenerator(databaseContext, Globals.prefs.getCitationKeyPatternPreferences()); for (BibEntry entry : entries) { keyGenerator.generateAndSetKey(entry) .ifPresent(fieldChange -> compound.addEdit(new UndoableKeyChange(fieldChange))); @@ -102,7 +103,7 @@ private void generateKeys() { } frame.getCurrentBasePanel().markBaseChanged(); - dialogService.notify(formatOutputMessage(Localization.lang("Generated BibTeX key for"), entries.size())); + dialogService.notify(formatOutputMessage(Localization.lang("Generated citation key for"), entries.size())); }); } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeySingleAction.java b/src/main/java/org/jabref/gui/citationkeypattern/GenerateCitationKeySingleAction.java similarity index 60% rename from src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeySingleAction.java rename to src/main/java/org/jabref/gui/citationkeypattern/GenerateCitationKeySingleAction.java index 7e8501dbcd8..43e2acbe1ef 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeySingleAction.java +++ b/src/main/java/org/jabref/gui/citationkeypattern/GenerateCitationKeySingleAction.java @@ -1,16 +1,16 @@ -package org.jabref.gui.bibtexkeypattern; +package org.jabref.gui.citationkeypattern; import javax.swing.undo.UndoManager; import org.jabref.gui.DialogService; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.undo.UndoableKeyChange; -import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; +import org.jabref.logic.citationkeypattern.CitationKeyGenerator; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.PreferencesService; -public class GenerateBibtexKeySingleAction extends SimpleCommand { +public class GenerateCitationKeySingleAction extends SimpleCommand { private final DialogService dialogService; private final BibDatabaseContext databaseContext; @@ -18,22 +18,22 @@ public class GenerateBibtexKeySingleAction extends SimpleCommand { private final BibEntry entry; private final UndoManager undoManager; - public GenerateBibtexKeySingleAction(BibEntry entry, BibDatabaseContext databaseContext, DialogService dialogService, PreferencesService preferencesService, UndoManager undoManager) { + public GenerateCitationKeySingleAction(BibEntry entry, BibDatabaseContext databaseContext, DialogService dialogService, PreferencesService preferencesService, UndoManager undoManager) { this.entry = entry; this.databaseContext = databaseContext; this.dialogService = dialogService; this.preferencesService = preferencesService; this.undoManager = undoManager; - if (preferencesService.getBibtexKeyPatternPreferences().shouldAvoidOverwriteCiteKey()) { + if (preferencesService.getCitationKeyPatternPreferences().shouldAvoidOverwriteCiteKey()) { this.executable.bind(entry.getCiteKeyBinding().isEmpty()); } } @Override public void execute() { - if (!entry.hasCiteKey() || GenerateBibtexKeyAction.confirmOverwriteKeys(dialogService)) { - new BibtexKeyGenerator(databaseContext, preferencesService.getBibtexKeyPatternPreferences()) + if (!entry.hasCiteKey() || GenerateCitationKeyAction.confirmOverwriteKeys(dialogService)) { + new CitationKeyGenerator(databaseContext, preferencesService.getCitationKeyPatternPreferences()) .generateAndSetKey(entry) .ifPresent(change -> undoManager.addEdit(new UndoableKeyChange(change))); } diff --git a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanel.fxml b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanel.fxml similarity index 90% rename from src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanel.fxml rename to src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanel.fxml index 861cec5714b..57936b93824 100644 --- a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanel.fxml +++ b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanel.fxml @@ -4,7 +4,7 @@ + fx:controller="org.jabref.gui.commonfxcontrols.CitationKeyPatternPanel"> diff --git a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanel.java similarity index 70% rename from src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanel.java rename to src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanel.java index b4c8db1605c..42b28084211 100644 --- a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanel.java @@ -14,28 +14,28 @@ import org.jabref.gui.icon.IconTheme; import org.jabref.gui.util.ValueTableCellFactory; import org.jabref.logic.l10n.Localization; -import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; +import org.jabref.model.bibtexkeypattern.AbstractCitationKeyPattern; import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.types.EntryType; import org.jabref.preferences.JabRefPreferences; import com.airhacks.afterburner.views.ViewLoader; -public class BibtexKeyPatternPanel extends TableView { +public class CitationKeyPatternPanel extends TableView { - @FXML public TableColumn entryTypeColumn; - @FXML public TableColumn patternColumn; - @FXML public TableColumn actionsColumn; + @FXML public TableColumn entryTypeColumn; + @FXML public TableColumn patternColumn; + @FXML public TableColumn actionsColumn; - private BibtexKeyPatternPanelViewModel viewModel; + private CitationKeyPatternPanelViewModel viewModel; private long lastKeyPressTime; private String tableSearchTerm; - public BibtexKeyPatternPanel(JabRefPreferences preferences, Collection entryTypeList, AbstractBibtexKeyPattern keyPattern) { + public CitationKeyPatternPanel(JabRefPreferences preferences, Collection entryTypeList, AbstractCitationKeyPattern keyPattern) { super(); - viewModel = new BibtexKeyPatternPanelViewModel(preferences, entryTypeList, keyPattern); + viewModel = new CitationKeyPatternPanelViewModel(preferences, entryTypeList, keyPattern); ViewLoader.view(this) .root(this) @@ -49,11 +49,11 @@ private void initialize() { entryTypeColumn.setSortable(true); entryTypeColumn.setReorderable(false); entryTypeColumn.setCellValueFactory(cellData -> cellData.getValue().entryType()); - new ValueTableCellFactory() + new ValueTableCellFactory() .withText(EntryType::getDisplayName) .install(entryTypeColumn); this.setOnSort(event -> - viewModel.patternListProperty().sort(BibtexKeyPatternPanelViewModel.defaultOnTopComparator)); + viewModel.patternListProperty().sort(CitationKeyPatternPanelViewModel.defaultOnTopComparator)); patternColumn.setSortable(true); patternColumn.setReorderable(false); @@ -61,13 +61,13 @@ private void initialize() { patternColumn.setCellFactory(TextFieldTableCell.forTableColumn()); patternColumn.setEditable(true); patternColumn.setOnEditCommit( - (TableColumn.CellEditEvent event) -> + (TableColumn.CellEditEvent event) -> event.getRowValue().setPattern(event.getNewValue())); actionsColumn.setSortable(false); actionsColumn.setReorderable(false); actionsColumn.setCellValueFactory(cellData -> cellData.getValue().entryType()); - new ValueTableCellFactory() + new ValueTableCellFactory() .withGraphic(entryType -> IconTheme.JabRefIcons.REFRESH.getGraphicNode()) .withTooltip(entryType -> String.format(Localization.lang("Reset %s to default value"), entryType.getDisplayName())) @@ -88,11 +88,11 @@ public void resetAll() { viewModel.resetAll(); } - public ListProperty patternListProperty() { + public ListProperty patternListProperty() { return viewModel.patternListProperty(); } - public ObjectProperty defaultKeyPatternProperty() { + public ObjectProperty defaultKeyPatternProperty() { return viewModel.defaultKeyPatternProperty(); } @@ -113,15 +113,15 @@ private void jumpToSearchKey(KeyEvent keypressed) { .findFirst().ifPresent(this::scrollTo); } - private static class HighlightTableRow extends TableRow { + private static class HighlightTableRow extends TableRow { @Override - public void updateItem(BibtexKeyPatternPanelItemModel item, boolean empty) { + public void updateItem(CitationKeyPatternPanelItemModel item, boolean empty) { super.updateItem(item, empty); if (item == null || item.getEntryType() == null) { setStyle(""); } else if (isSelected()) { setStyle("-fx-background-color: -fx-selection-bar"); - } else if (item.getEntryType().getName().equals(BibtexKeyPatternPanelViewModel.ENTRY_TYPE_DEFAULT_NAME)) { + } else if (item.getEntryType().getName().equals(CitationKeyPatternPanelViewModel.ENTRY_TYPE_DEFAULT_NAME)) { setStyle("-fx-background-color: -fx-default-button"); } else { setStyle(""); diff --git a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanelItemModel.java b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanelItemModel.java similarity index 90% rename from src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanelItemModel.java rename to src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanelItemModel.java index 5e6777ef62f..61b7ce6a61c 100644 --- a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanelItemModel.java +++ b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanelItemModel.java @@ -9,11 +9,11 @@ import org.jabref.model.entry.types.EntryType; -public class BibtexKeyPatternPanelItemModel { +public class CitationKeyPatternPanelItemModel { private final ObjectProperty entryType = new SimpleObjectProperty<>(); private final StringProperty pattern = new SimpleStringProperty(""); - public BibtexKeyPatternPanelItemModel(EntryType entryType, String pattern) { + public CitationKeyPatternPanelItemModel(EntryType entryType, String pattern) { Objects.requireNonNull(entryType); Objects.requireNonNull(pattern); this.entryType.setValue(entryType); diff --git a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanelViewModel.java b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanelViewModel.java similarity index 68% rename from src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanelViewModel.java rename to src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanelViewModel.java index 6e271e18f90..6f906b98c38 100644 --- a/src/main/java/org/jabref/gui/commonfxcontrols/BibtexKeyPatternPanelViewModel.java +++ b/src/main/java/org/jabref/gui/commonfxcontrols/CitationKeyPatternPanelViewModel.java @@ -10,16 +10,16 @@ import javafx.collections.FXCollections; import org.jabref.logic.l10n.Localization; -import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; +import org.jabref.model.bibtexkeypattern.AbstractCitationKeyPattern; import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.types.EntryType; import org.jabref.preferences.JabRefPreferences; -public class BibtexKeyPatternPanelViewModel { +public class CitationKeyPatternPanelViewModel { public static final String ENTRY_TYPE_DEFAULT_NAME = "default"; - public static Comparator defaultOnTopComparator = (o1, o2) -> { + public static Comparator defaultOnTopComparator = (o1, o2) -> { String itemOneName = o1.getEntryType().getName(); String itemTwoName = o2.getEntryType().getName(); @@ -34,13 +34,13 @@ public class BibtexKeyPatternPanelViewModel { return 0; }; - private final ListProperty patternListProperty = new SimpleListProperty<>(); - private final ObjectProperty defaultItemProperty = new SimpleObjectProperty<>(); - private final AbstractBibtexKeyPattern initialKeyPattern; + private final ListProperty patternListProperty = new SimpleListProperty<>(); + private final ObjectProperty defaultItemProperty = new SimpleObjectProperty<>(); + private final AbstractCitationKeyPattern initialKeyPattern; private final Collection bibEntryTypeList; private final JabRefPreferences preferences; - public BibtexKeyPatternPanelViewModel(JabRefPreferences preferences, Collection entryTypeList, AbstractBibtexKeyPattern initialKeyPattern) { + public CitationKeyPatternPanelViewModel(JabRefPreferences preferences, Collection entryTypeList, AbstractCitationKeyPattern initialKeyPattern) { this.preferences = preferences; this.bibEntryTypeList = entryTypeList; this.initialKeyPattern = initialKeyPattern; @@ -54,7 +54,7 @@ public void setValues() { defaultPattern = initialKeyPattern.getDefaultValue().get(0); } - defaultItemProperty.setValue(new BibtexKeyPatternPanelItemModel(new DefaultEntryType(), defaultPattern)); + defaultItemProperty.setValue(new CitationKeyPatternPanelItemModel(new DefaultEntryType(), defaultPattern)); patternListProperty.setValue(FXCollections.observableArrayList()); patternListProperty.add(defaultItemProperty.getValue()); @@ -67,24 +67,24 @@ public void setValues() { } else { pattern = initialKeyPattern.getPatterns().get(entryType).get(0); } - patternListProperty.add(new BibtexKeyPatternPanelItemModel(entryType, pattern)); + patternListProperty.add(new CitationKeyPatternPanelItemModel(entryType, pattern)); }); } - public void setItemToDefaultPattern(BibtexKeyPatternPanelItemModel item) { - item.setPattern((String) preferences.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + public void setItemToDefaultPattern(CitationKeyPatternPanelItemModel item) { + item.setPattern((String) preferences.defaults.get(JabRefPreferences.DEFAULT_CITATION_KEY_PATTERN)); } public void resetAll() { patternListProperty.forEach(item -> item.setPattern("")); - defaultItemProperty.getValue().setPattern((String) preferences.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + defaultItemProperty.getValue().setPattern((String) preferences.defaults.get(JabRefPreferences.DEFAULT_CITATION_KEY_PATTERN)); } - public ListProperty patternListProperty() { + public ListProperty patternListProperty() { return patternListProperty; } - public ObjectProperty defaultKeyPatternProperty() { + public ObjectProperty defaultKeyPatternProperty() { return defaultItemProperty; } diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java index 86ecc9980b3..2e91b67a4b7 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java @@ -3,16 +3,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; import javafx.beans.Observable; -import javafx.beans.property.ListProperty; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -34,7 +30,6 @@ import org.jabref.model.entry.types.UnknownEntryType; import org.jabref.preferences.PreferencesService; -import com.tobiasdiez.easybind.EasyBind; import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; import de.saxsys.mvvmfx.utils.validation.ValidationMessage; import de.saxsys.mvvmfx.utils.validation.ValidationStatus; @@ -55,18 +50,14 @@ public Field fromString(String string) { } }; - private final ListProperty entryTypes; - private final ListProperty fields; - private final ObjectProperty selectedEntryTypes = new SimpleObjectProperty<>(); - private final ListProperty fieldsForType; + private final ObservableList fieldsForAdding = FXCollections.observableArrayList(FieldFactory.getStandardFielsdsWithBibTexKey()); + private final ObjectProperty selectedEntryType = new SimpleObjectProperty<>(); private final ObjectProperty selectedFieldToAdd = new SimpleObjectProperty<>(); private final StringProperty entryTypeToAdd = new SimpleStringProperty(""); - private final ObservableList allEntryTypes; - private final ObservableList allFieldsForType = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.fieldName(), extractor.fieldType()}); private final ObjectProperty newFieldToAdd = new SimpleObjectProperty<>(); private final BibDatabaseMode mode; - private final Map> typesWithFields = new HashMap<>(); - private final List typesToRemove = new ArrayList<>(); + private final ObservableList entryTypesWithFields = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.entryType(), extractor.fields()}); + private final List entryTypesToDelete = new ArrayList<>(); private final PreferencesService preferencesService; private final BibEntryTypesManager entryTypesManager; @@ -79,40 +70,33 @@ public CustomEntryTypeDialogViewModel(BibDatabaseMode mode, PreferencesService p this.preferencesService = preferencesService; this.entryTypesManager = entryTypesManager; - Collection allTypes = entryTypesManager.getAllTypes(mode); - allTypes.addAll(entryTypesManager.getAllCustomTypes(mode)); + addAllTypes(); - allEntryTypes = FXCollections.observableArrayList(allTypes); - entryTypes = new SimpleListProperty<>(allEntryTypes); + Predicate notEmpty = input -> (input != null) && !input.trim().isEmpty(); + entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name."))); + fieldValidator = new FunctionBasedValidator<>(newFieldToAdd, + input -> (input != null) && !input.getDisplayName().isEmpty(), + ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name."))); + } - fields = new SimpleListProperty<>(FXCollections.observableArrayList(FieldFactory.getCommonFields())); + public void addAllTypes() { + if (this.entryTypesWithFields.size() > 0) { + this.entryTypesWithFields.clear(); + } + Collection allTypes = entryTypesManager.getAllTypes(mode); for (BibEntryType entryType : allTypes) { - List fields = entryType.getAllFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority(), entryType)).collect(Collectors.toList()); - typesWithFields.put(entryType, fields); + CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(entryType); + this.entryTypesWithFields.add(viewModel); } - - this.fieldsForType = new SimpleListProperty<>(allFieldsForType); - - EasyBind.subscribe(selectedEntryTypes, type -> { - if (type != null) { - allFieldsForType.setAll(typesWithFields.get(type)); - } - }); - - Predicate notEmpty = input -> (input != null) && !input.trim().isEmpty(); - entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name."))); - fieldValidator = new FunctionBasedValidator<>(newFieldToAdd, - input -> input != null && !input.getDisplayName().isEmpty(), - ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name."))); } - public ListProperty entryTypes() { - return this.entryTypes; + public ObservableList entryTypes() { + return this.entryTypesWithFields; } - public ListProperty fields() { - return this.fields; + public ObservableList fieldsForAdding() { + return this.fieldsForAdding; } public enum FieldType { @@ -138,26 +122,23 @@ public String toString() { public void addNewField() { Field field = newFieldToAdd.getValue(); - FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT, selectedEntryTypes.getValue()); - typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).add(model); - allFieldsForType.add(model); + FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT); + this.selectedEntryType.getValue().addField(model); newFieldToAddProperty().setValue(null); } - public void addNewCustomEntryType() { + public CustomEntryTypeViewModel addNewCustomEntryType() { EntryType newentryType = new UnknownEntryType(entryTypeToAdd.getValue()); BibEntryType type = new BibEntryType(newentryType, new ArrayList<>(), Collections.emptyList()); - this.allEntryTypes.add(type); + CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(type); + this.entryTypesWithFields.add(viewModel); this.entryTypeToAdd.setValue(""); - this.typesWithFields.put(type, new ArrayList<>()); - } - public ObjectProperty selectedEntryTypeProperty() { - return this.selectedEntryTypes; + return viewModel; } - public ListProperty fieldsforTypesProperty() { - return this.fieldsForType; + public ObjectProperty selectedEntryTypeProperty() { + return this.selectedEntryType; } public ObjectProperty selectedFieldToAddProperty() { @@ -180,22 +161,27 @@ public ValidationStatus fieldValidationStatus() { return fieldValidator.getValidationStatus(); } - public void removeEntryType(BibEntryType focusedItem) { - typesToRemove.add(focusedItem); - typesWithFields.remove(focusedItem); - allEntryTypes.remove(focusedItem); + public void removeEntryType(CustomEntryTypeViewModel focusedItem) { + entryTypesWithFields.remove(focusedItem); + entryTypesToDelete.add(focusedItem.entryType().getValue()); } public void removeField(FieldViewModel focusedItem) { - typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).remove(focusedItem); - allFieldsForType.remove(focusedItem); + selectedEntryType.getValue().removeField(focusedItem); + } + + public void resetAllCustomEntryTypes() { + entryTypesManager.clearAllCustomEntryTypes(mode); + preferencesService.clearBibEntryTypes(mode); + entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX), + preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); } public void apply() { - for (var typeWithField : typesWithFields.entrySet()) { - BibEntryType type = typeWithField.getKey(); - List allFields = typeWithField.getValue(); + for (var typeWithField : entryTypesWithFields) { + BibEntryType type = typeWithField.entryType().getValue(); + List allFields = typeWithField.fields(); List requiredFields = allFields.stream().filter(field -> field.getFieldType() == FieldType.REQUIRED).map(FieldViewModel::getField).map(OrFields::new).collect(Collectors.toList()); List otherFields = allFields.stream().filter(field -> field.getFieldType() == FieldType.OPTIONAL).map(bibField -> new BibField(bibField.getField(), bibField.getFieldPriority())).collect(Collectors.toList()); @@ -204,13 +190,13 @@ public void apply() { entryTypesManager.addCustomOrModifiedType(newType, mode); } - for (var type : typesToRemove) { - entryTypesManager.removeCustomOrModifiedEntryType(type, mode); + for (var entryType : entryTypesToDelete) { + entryTypesManager.removeCustomOrModifiedEntryType(entryType, mode); } - preferencesService.saveCustomEntryTypes(); + + preferencesService.saveCustomEntryTypes(entryTypesManager); // Reload types from preferences to make sure any modifications are present when reopening the dialog - entryTypesManager.addCustomOrModifiedTypes( - preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX), - preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); + entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX), + preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); } } diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeViewModel.java b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeViewModel.java new file mode 100644 index 00000000000..4c9de9f9416 --- /dev/null +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeViewModel.java @@ -0,0 +1,64 @@ +package org.jabref.gui.customentrytypes; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import org.jabref.model.entry.BibEntryType; + +public class CustomEntryTypeViewModel { + + private final ObjectProperty entryType = new SimpleObjectProperty<>(); + private final ObservableList fields; + + public CustomEntryTypeViewModel(BibEntryType entryType) { + this.entryType.set(entryType); + + List allFieldsForType = entryType.getAllBibFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority())).collect(Collectors.toList()); + fields = FXCollections.observableArrayList((allFieldsForType)); + } + + @Override + public int hashCode() { + return Objects.hash(entryType, fields); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof CustomEntryTypeViewModel)) { + return false; + } + CustomEntryTypeViewModel other = (CustomEntryTypeViewModel) obj; + return Objects.equals(entryType, other.entryType) && Objects.equals(fields, other.fields); + } + + public void addField(FieldViewModel field) { + this.fields.add(field); + } + + public ObservableList fields() { + return this.fields; + } + + public ObjectProperty entryType() { + return this.entryType; + } + + public void removeField(FieldViewModel focusedItem) { + this.fields.remove(focusedItem); + } + + @Override + public String toString() { + return "CustomEntryTypeViewModel [entryType=" + entryType + ", fields=" + fields + "]"; + } + +} diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml index 8e45dc99d80..700338d89af 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml @@ -96,4 +96,5 @@ + diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java index 0996859bcab..38ecf48af78 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java @@ -6,29 +6,42 @@ import javafx.application.Platform; import javafx.beans.property.ReadOnlyStringWrapper; +import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ButtonBar.ButtonData; import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.TextField; - +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DragEvent; +import javafx.scene.input.Dragboard; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.TransferMode; + +import org.jabref.gui.DialogService; +import org.jabref.gui.DragAndDropDataFormats; +import org.jabref.gui.StateManager; import org.jabref.gui.customentrytypes.CustomEntryTypeDialogViewModel.FieldType; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ControlHelper; +import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.gui.util.RadioButtonCell; import org.jabref.gui.util.ValueTableCellFactory; +import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.entry.field.Field; import org.jabref.preferences.PreferencesService; import com.airhacks.afterburner.views.ViewLoader; +import com.tobiasdiez.easybind.EasyBind; import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; public class CustomizeEntryTypeDialogView extends BaseDialog { @@ -36,9 +49,9 @@ public class CustomizeEntryTypeDialogView extends BaseDialog { private final BibDatabaseMode mode; private final BibEntryTypesManager entryTypesManager; - @FXML private TableView entryTypes; - @FXML private TableColumn entryTypColumn; - @FXML private TableColumn entryTypeActionsColumn; + @FXML private TableView entryTypes; + @FXML private TableColumn entryTypColumn; + @FXML private TableColumn entryTypeActionsColumn; @FXML private TextField addNewEntryType; @FXML private TableView fields; @FXML private TableColumn fieldNameColumn; @@ -46,13 +59,18 @@ public class CustomizeEntryTypeDialogView extends BaseDialog { @FXML private TableColumn fieldTypeActionColumn; @FXML private ComboBox addNewField; @FXML private ButtonType applyButton; + @FXML private ButtonType resetButton; @FXML private Button addNewEntryTypeButton; @FXML private Button addNewFieldButton; + @Inject private PreferencesService preferencesService; + @Inject private StateManager stateManager; + @Inject private DialogService dialogService; private CustomEntryTypeDialogViewModel viewModel; private final ControlsFxVisualizer visualizer = new ControlsFxVisualizer(); + private CustomLocalDragboard localDragboard; public CustomizeEntryTypeDialogView(BibDatabaseContext bibDatabaseContext, BibEntryTypesManager entryTypesManager) { this.mode = bibDatabaseContext.getMode(); @@ -68,10 +86,14 @@ public CustomizeEntryTypeDialogView(BibDatabaseContext bibDatabaseContext, BibEn } return null; }); + ControlHelper.setAction(resetButton, getDialogPane(), event -> this.resetEntryTypes()); } @FXML private void initialize() { + // As the state manager gets injected it's not available in the constructor + this.localDragboard = stateManager.getLocalDragboard(); + viewModel = new CustomEntryTypeDialogViewModel(mode, preferencesService, entryTypesManager); setupTable(); @@ -88,14 +110,14 @@ private void setupTable() { // Table View must be editable, otherwise the change of the Radiobuttons does not propagate the commit event fields.setEditable(true); - entryTypColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getType().getDisplayName())); - entryTypes.itemsProperty().bind(viewModel.entryTypes()); + entryTypColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().entryType().get().getType().getDisplayName())); + entryTypes.setItems(viewModel.entryTypes()); entryTypes.getSelectionModel().selectFirst(); entryTypeActionsColumn.setSortable(false); entryTypeActionsColumn.setReorderable(false); - entryTypeActionsColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getType().getDisplayName())); - new ValueTableCellFactory() + entryTypeActionsColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().entryType().get().getType().getDisplayName())); + new ValueTableCellFactory() .withGraphic(item -> IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode()) .withTooltip(name -> Localization.lang("Remove entry type") + " " + name) .withOnMouseClickedEvent(item -> evt -> viewModel.removeEntryType(entryTypes.getSelectionModel().getSelectedItem())) @@ -114,7 +136,7 @@ private void setupTable() { viewModel.selectedEntryTypeProperty().bind(entryTypes.getSelectionModel().selectedItemProperty()); viewModel.entryTypeToAddProperty().bindBidirectional(addNewEntryType.textProperty()); - addNewField.setItems(viewModel.fields()); + addNewField.setItems(viewModel.fieldsForAdding()); addNewField.setConverter(viewModel.FIELD_STRING_CONVERTER); fieldTypeActionColumn.setSortable(false); @@ -128,16 +150,86 @@ private void setupTable() { .install(fieldTypeActionColumn); viewModel.newFieldToAddProperty().bindBidirectional(addNewField.valueProperty()); - fields.itemsProperty().bindBidirectional(viewModel.fieldsforTypesProperty()); + + EasyBind.subscribe(viewModel.selectedEntryTypeProperty(), type -> { + if (type != null) { + var items = type.fields(); + fields.setItems(items); + } + }); + + new ViewModelTableRowFactory() + .setOnDragDetected(this::handleOnDragDetected) + .setOnDragDropped(this::handleOnDragDropped) + .setOnDragOver(this::handleOnDragOver) + .install(fields); +} + + private void handleOnDragOver(FieldViewModel originalItem, DragEvent event) { + if ((event.getGestureSource() != originalItem) && event.getDragboard().hasContent(DragAndDropDataFormats.FIELD)) { + event.acceptTransferModes(TransferMode.MOVE); + } + } + + private void handleOnDragDetected(TableRow row, FieldViewModel fieldViewModel, MouseEvent event) { + row.startFullDrag(); + FieldViewModel field = fields.getSelectionModel().getSelectedItem(); + + ClipboardContent content = new ClipboardContent(); + Dragboard dragboard = fields.startDragAndDrop(TransferMode.MOVE); + content.put(DragAndDropDataFormats.FIELD, ""); + localDragboard.putValue(FieldViewModel.class, field); + dragboard.setContent(content); + event.consume(); + } + + private void handleOnDragDropped(TableRow row, FieldViewModel originalItem, DragEvent event) { + boolean success = false; + + ObservableList items = fields.itemsProperty().get(); + + if (localDragboard.hasType(FieldViewModel.class)) { + FieldViewModel field = localDragboard.getValue(FieldViewModel.class); + int draggedIdx = 0; + for (int i = 0; i < items.size(); i++) { + if (items.get(i).equals(field)) { + draggedIdx = i; + field = items.get(i); + break; + } + } + int thisIdx = items.indexOf(originalItem); + items.set(draggedIdx, originalItem); + items.set(thisIdx, field); + success = true; + } + + event.setDropCompleted(success); + event.consume(); } @FXML void addEntryType() { - viewModel.addNewCustomEntryType(); + CustomEntryTypeViewModel newlyAdded = viewModel.addNewCustomEntryType(); + this.entryTypes.getSelectionModel().select(newlyAdded); + this.entryTypes.scrollTo(newlyAdded); } @FXML void addNewField() { viewModel.addNewField(); } + + private void resetEntryTypes() { + boolean reset = dialogService.showConfirmationDialogAndWait( + Localization.lang("Reset entry types and fields to defaults"), + Localization.lang("This will reset all entry types to their default values and remove all custom entry types"), + Localization.lang("Reset to default")); + if (reset) { + viewModel.resetAllCustomEntryTypes(); + viewModel.addAllTypes(); + this.entryTypes.refresh(); + } + + } } diff --git a/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java b/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java index ae2f0f853fc..7cb538e4b17 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java +++ b/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java @@ -6,7 +6,6 @@ import javafx.beans.property.StringProperty; import org.jabref.gui.customentrytypes.CustomEntryTypeDialogViewModel.FieldType; -import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldPriority; @@ -16,18 +15,16 @@ public class FieldViewModel { private final StringProperty fieldName = new SimpleStringProperty(""); private final Field field; private final FieldPriority fieldPriority; - private BibEntryType entryType; - public FieldViewModel(Field field, FieldType fieldType, FieldPriority fieldPriority, BibEntryType entryType) { + public FieldViewModel(Field field, FieldType fieldType, FieldPriority fieldPriority) { this.field = field; - this.entryType = entryType; this.fieldName.setValue(field.getDisplayName()); this.fieldType = new SimpleObjectProperty<>(fieldType); this.fieldPriority = fieldPriority; } - public FieldViewModel(Field field, boolean required, FieldPriority fieldPriority, BibEntryType entryType) { - this(field, required ? FieldType.REQUIRED : FieldType.OPTIONAL, fieldPriority, entryType); + public FieldViewModel(Field field, boolean required, FieldPriority fieldPriority) { + this(field, required ? FieldType.REQUIRED : FieldType.OPTIONAL, fieldPriority); } public ObjectProperty fieldType() { @@ -42,10 +39,6 @@ public Field getField() { return this.field; } - public BibEntryType getEntryType() { - return this.entryType; - } - public FieldPriority getFieldPriority() { return this.fieldPriority; } diff --git a/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java b/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java index 5a4869990c1..cfbd0eda0a2 100644 --- a/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java @@ -8,7 +8,7 @@ import javafx.beans.property.StringProperty; import org.jabref.gui.DialogService; -import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; +import org.jabref.logic.citationkeypattern.CitationKeyGenerator; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; @@ -58,8 +58,12 @@ public void saveFields() { return; } - String testString = BibtexKeyGenerator.cleanKey(parts[1], preferences.getUnwantedCharacters()); - if (!testString.equals(parts[1]) || (parts[1].indexOf('&') >= 0)) { + // Use literal string of unwanted characters specified below as opposed to exporting characters + // from preferences because the list of allowable characters in this particular differs + // i.e. ';' character is allowed in this window, but it's on the list of unwanted chars in preferences + String unwantedChars = "#{}()~,^&-\"'`ʹ\\"; + String testString = CitationKeyGenerator.cleanKey(parts[1], unwantedChars); + if (!testString.equals(parts[1])) { dialogService.showInformationDialogAndWait( Localization.lang("Error"), Localization.lang("Field names are not allowed to contain white spaces or certain characters (%0).", diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java index 545593c641a..ccc8c3e507c 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateResolverDialog.java @@ -6,10 +6,12 @@ import javafx.scene.control.ButtonType; import javafx.scene.layout.BorderPane; +import org.jabref.gui.StateManager; import org.jabref.gui.duplicationFinder.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.help.HelpAction; import org.jabref.gui.mergeentries.MergeEntries; import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.DialogWindowState; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; @@ -18,6 +20,7 @@ public class DuplicateResolverDialog extends BaseDialog { private final BibDatabaseContext database; + private final StateManager stateManager; public enum DuplicateResolverType { DUPLICATE_SEARCH, @@ -37,9 +40,10 @@ public enum DuplicateResolverResult { private MergeEntries me; - public DuplicateResolverDialog(BibEntry one, BibEntry two, DuplicateResolverType type, BibDatabaseContext database) { + public DuplicateResolverDialog(BibEntry one, BibEntry two, DuplicateResolverType type, BibDatabaseContext database, StateManager stateManager) { this.setTitle(Localization.lang("Possible duplicate entries")); this.database = database; + this.stateManager = stateManager; init(one, two, type); } @@ -95,10 +99,20 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { this.getDialogPane().getButtonTypes().addAll(first, second, both, merge, cancel, help); + // Retrieves the previous window state and sets the new dialog window size and position to match it + DialogWindowState state = stateManager.getDialogWindowState(getClass().getSimpleName()); + if (state != null) { + this.getDialogPane().setPrefSize(state.getWidth(), state.getHeight()); + this.setX(state.getX()); + this.setY(state.getY()); + } + BorderPane borderPane = new BorderPane(me); borderPane.setBottom(options); this.setResultConverter(button -> { + // Updates the window state on button press + stateManager.setDialogWindowState(getClass().getSimpleName(), new DialogWindowState(this.getX(), this.getY(), this.getDialogPane().getHeight(), this.getDialogPane().getWidth())); if (button.equals(first)) { return DuplicateResolverResult.KEEP_LEFT; diff --git a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java index a249719bb50..eeb4528de9f 100644 --- a/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/duplicationFinder/DuplicateSearch.java @@ -131,7 +131,7 @@ private DuplicateSearchResult verifyDuplicates() { } private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, BibEntry second, DuplicateResolverType resolverType) { - DuplicateResolverDialog dialog = new DuplicateResolverDialog(first, second, resolverType, frame.getCurrentBasePanel().getBibDatabaseContext()); + DuplicateResolverDialog dialog = new DuplicateResolverDialog(first, second, resolverType, frame.getCurrentBasePanel().getBibDatabaseContext(), stateManager); DuplicateResolverResult resolverResult = dialog.showAndWait().orElse(DuplicateResolverResult.BREAK); diff --git a/src/main/java/org/jabref/gui/edit/CopyMoreAction.java b/src/main/java/org/jabref/gui/edit/CopyMoreAction.java index b962d2f0c91..5f982b01da3 100644 --- a/src/main/java/org/jabref/gui/edit/CopyMoreAction.java +++ b/src/main/java/org/jabref/gui/edit/CopyMoreAction.java @@ -109,7 +109,7 @@ private void copyKey() { .collect(Collectors.toList()); if (keys.isEmpty()) { - dialogService.notify(Localization.lang("None of the selected entries have BibTeX keys.")); + dialogService.notify(Localization.lang("None of the selected entries have citation keys.")); return; } @@ -121,7 +121,7 @@ private void copyKey() { dialogService.notify(Localization.lang("Copied '%0' to clipboard.", JabRefDialogService.shortenDialogMessage(copiedKeys))); } else { - dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", + dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined citation key.", Integer.toString(entries.size() - keys.size()), Integer.toString(entries.size()))); } } @@ -136,7 +136,7 @@ private void copyCiteKey() { .collect(Collectors.toList()); if (keys.isEmpty()) { - dialogService.notify(Localization.lang("None of the selected entries have BibTeX keys.")); + dialogService.notify(Localization.lang("None of the selected entries have citation keys.")); return; } @@ -152,7 +152,7 @@ private void copyCiteKey() { dialogService.notify(Localization.lang("Copied '%0' to clipboard.", JabRefDialogService.shortenDialogMessage(copiedCiteCommand))); } else { - dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", + dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined citation key.", Integer.toString(entries.size() - keys.size()), Integer.toString(entries.size()))); } } @@ -182,7 +182,7 @@ private void copyKeyAndTitle() { } if (entriesWithKeys == 0) { - dialogService.notify(Localization.lang("None of the selected entries have BibTeX keys.")); + dialogService.notify(Localization.lang("None of the selected entries have citation keys.")); return; } @@ -193,15 +193,15 @@ private void copyKeyAndTitle() { dialogService.notify(Localization.lang("Copied '%0' to clipboard.", JabRefDialogService.shortenDialogMessage(keyAndTitle.toString()))); } else { - dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", + dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined citation key.", Integer.toString(entries.size() - entriesWithKeys), Integer.toString(entries.size()))); } } /** - * This method will copy each selected entry's BibTeX key as a hyperlink to its url to the clipboard. In case an - * entry doesn't have a BibTeX key it will not be copied. In case an entry doesn't have an url this will only copy - * the BibTeX key. + * This method will copy each selected entry's citation key as a hyperlink to its url to the clipboard. In case an + * entry doesn't have a citation key it will not be copied. In case an entry doesn't have an url this will only copy + * the citation key. */ private void copyKeyAndLink() { List entries = stateManager.getSelectedEntries(); @@ -213,7 +213,7 @@ private void copyKeyAndLink() { .collect(Collectors.toList()); if (entriesWithKey.isEmpty()) { - dialogService.notify(Localization.lang("None of the selected entries have BibTeX keys.")); + dialogService.notify(Localization.lang("None of the selected entries have citation keys.")); return; } @@ -231,7 +231,7 @@ private void copyKeyAndLink() { dialogService.notify(Localization.lang("Copied '%0' to clipboard.", JabRefDialogService.shortenDialogMessage(keyAndLink.toString()))); } else { - dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", + dialogService.notify(Localization.lang("Warning: %0 out of %1 entries have undefined citation key.", Long.toString(entries.size() - entriesWithKey.size()), Integer.toString(entries.size()))); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java index af274875217..883bc98da1e 100644 --- a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java @@ -1,11 +1,8 @@ package org.jabref.gui.entryeditor; import java.util.Collections; -import java.util.Comparator; import java.util.Optional; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.stream.Collectors; +import java.util.Set; import javax.swing.undo.UndoManager; @@ -39,16 +36,14 @@ public DeprecatedFieldsTab(BibDatabaseContext databaseContext, SuggestionProvide } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { Optional entryType = entryTypesManager.enrich(entry.getType(), databaseContext.getMode()); if (entryType.isPresent()) { - return entryType.get().getDeprecatedFields() - .stream() - .filter(entry::hasField) - .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName)))); + return entryType.get().getDeprecatedFields(); + } else { // Entry type unknown -> treat all fields as required - return Collections.emptySortedSet(); + return Collections.emptySet(); } } } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.fxml b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.fxml index 35fb41daa74..ce73a6e782a 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.fxml +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.fxml @@ -45,7 +45,7 @@ - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + +