diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..4cfebe1ba5d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Patreon user account +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: JabRef +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: https://github.com/JabRef/jabref/wiki/Donations # Replace with a single custom sponsorship URL diff --git a/CHANGELOG.md b/CHANGELOG.md index f711e4e8841..94035e915c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed +- All fields are now properly sorted alphabetically (in the subgroups of required/optional fields) when the entry is written to the bib file. +- We fixed an issue where some importers used the field `pubstatus` instead of the standard BibTeX field `pubstate`. - We changed the latex command removal for docbook exporter. [#3838](https://github.com/JabRef/jabref/issues/3838) - We changed the location of some fields in the entry editor (you might need to reset your preferences for these changes to come into effect) - Journal/Year/Month in biblatex mode -> Deprecated (if filled) @@ -53,17 +55,28 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - For automatically created groups, added ability to filter groups by entry type. [#4539](https://github.com/JabRef/jabref/issues/4539) - We added the ability to add field names from the Preferences Dialog [#4546](https://github.com/JabRef/jabref/issues/4546) - We added the ability change the column widths directly in the main table. [#4546](https://github.com/JabRef/jabref/issues/4546) +- We added description of how recommendations where chosen and better error handling to Related Articles tab - We added the ability to execute default action in dialog by using with Ctrl + Enter combination [#4496](https://github.com/JabRef/jabref/issues/4496) - We grouped and reordered the Main Menu (File, Edit, Library, Quality, Tools, and View tabs & icons). [#4666](https://github.com/JabRef/jabref/issues/4666) [#4667](https://github.com/JabRef/jabref/issues/4667) [#4668](https://github.com/JabRef/jabref/issues/4668) [#4669](https://github.com/JabRef/jabref/issues/4669) [#4670](https://github.com/JabRef/jabref/issues/4670) [#4671](https://github.com/JabRef/jabref/issues/4671) [#4672](https://github.com/JabRef/jabref/issues/4672) [#4673](https://github.com/JabRef/jabref/issues/4673) - We added additional modifiers (capitalize, titlecase and sentencecase) to the Bibtex key generator. [#1506](https://github.com/JabRef/jabref/issues/1506) -- We grouped the toolbar icons and changed the Open Library and Copy icons. [#4584](https://github.com/JabRef/jabref/issues/4584) +- We have migrated from the mysql jdbc connector to the mariadb one for better authentication scheme support. [#4746](https://github.com/JabRef/jabref/issues/4745) +- We grouped the toolbar icons and changed the Open Library and Copy icons. [#4584](https://github.com/JabRef/jabref/issues/4584) - We added a browse button next to the path text field for aux-based groups. [#4586](https://github.com/JabRef/jabref/issues/4586) - We changed the title of Group Dialog to "Add subgroup" from "Edit group" when we select Add subgroup option. - We enable import button only if entries are selected. [#4755](https://github.com/JabRef/jabref/issues/4755) - We made modifications to improve contrast of UI elements. [#4583](https://github.com/JabRef/jabref/issues/4583) +- We added a warning for empty BibTeX keys in the entry editor. [#4440](https://github.com/JabRef/jabref/issues/4440) - We added an option in the settings to set the default action in JabRef when right clicking on any entry in any database and selecting "Open folder". [#4763](https://github.com/JabRef/jabref/issues/4763) - The Medline fetcher now normalizes the author names according to the BibTeX-Standard [#4345](https://github.com/JabRef/jabref/issues/4345) - We added an option on the Linked File Viewer to rename the attached file of an entry directly on the JabRef. [#4844](https://github.com/JabRef/jabref/issues/4844) +- We added an option in the preference dialog box that allows user to enable helpful tooltips.[#3599](https://github.com/JabRef/jabref/issues/3599) +- We moved the dropdown menu for selecting the push-application from the toolbar into the external application preferences. [#674](https://github.com/JabRef/jabref/issues/674) +- We removed the alphabetical ordering of the custom tabs and updated the error message when trying to create a general field with a name containing an illegal character. [#5019](https://github.com/JabRef/jabref/issues/5019) +- We added a context menu to the bib(la)tex-source-editor to copy'n'paste. [#5007](https://github.com/JabRef/jabref/pull/5007) +- We added a tool that allows searching for citations in LaTeX files. It scans directories and shows which entries are used, how many times and where. +- We added a 'LaTeX citations' tab to the entry editor, to search for citations to the active entry in the LaTeX file directory. It can be disabled in the preferences dialog. +- We added an option in preferences to allow for integers in field "edition" when running database in bibtex mode. [#4680](https://github.com/JabRef/jabref/issues/4680) +- We added the ability to use negation in export filter layouts. [#5138](https://github.com/JabRef/jabref/pull/5138) ### Fixed @@ -114,7 +127,13 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where special characters where removed from non label key generation pattern parts [#4767](https://github.com/JabRef/jabref/issues/4767) - We fixed an issue where the RIS import would overwite the article date with the value of the acessed date [#4816](https://github.com/JabRef/jabref/issues/4816) - We fixed an issue where an NullPointer exception was thrown when a referenced entry in an Open/Libre Office document was no longer present in the library. Now an error message with the reference marker of the missing entry is shown. [#4932](https://github.com/JabRef/jabref/issues/4932) - +- We fixed an issue where a database exception related to a missing timezone was too big. [#4827](https://github.com/JabRef/jabref/issues/4827) +- We fixed an issue where the IEEE fetcher returned an error if no keywords were present in the result from the IEEE website [#4997](https://github.com/JabRef/jabref/issues/4997) +- We fixed an issue where the command line help text had several errors, and arguments and descriptions have been rewritten to simplify and detail them better. [#4932](https://github.com/JabRef/jabref/issues/2016) +- We fixed an issue where the same menu for changing entry type had two different sizes and weights. [#4977](https://github.com/JabRef/jabref/issues/4977) +- 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) ### Removed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64d5105299b..24c25a05b9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,15 @@ After reading through this guide, check out some good first issues to contribute to by clicking here: [Good First Issues](https://github.com/JabRef/jabref/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) ## Understanding the basics -We welcome contributions to JabRef and encourage to create a fork, clone, **create a new branch** (such as `fix-for-issue-121`), **work on the new branch — not master**, and create a pull request. -Be sure to create a **separate branch** for each improvement you implement. -Take a look at GitHub's excellent overview on the [GitHub flow](https://guides.github.com/introduction/flow/index.html) and their [pull request help documentation](https://help.github.com/articles/about-pull-requests/) for a detailed explanation and the explanation of [Feature Branch Workflow](https://de.atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow) for the idea behind this kind of development. - -We also have [code howtos](https://github.com/JabRef/jabref/wiki/Code-Howtos) and [guidelines for setting up a local workspace](https://github.com/JabRef/jabref/wiki/Guidelines-for-setting-up-a-local-workspace). - -In case you have any question, do not hesitate to write one of our [JabRef developers](https://github.com/orgs/JabRef/teams/developers) an email. -We should also be online at [gitter](https://gitter.im/JabRef/jabref). +We welcome contributions to JabRef and encourage you to follow the GitHub workflow specified below. If you are not familiar with this type of workflow, take a look at GitHub's excellent overview on the [GitHub flow](https://guides.github.com/introduction/flow/index.html) and the explanation of [Feature Branch Workflow](https://atlassian.com/git/tutorials/comparing-workflows#feature-branch-workflow) for the idea behind this kind of development. +1. Get the JabRef code on your local machine. Detailed instructions about this step can be found in our [guidelines for setting up a local workspace](https://github.com/JabRef/jabref/wiki/Guidelines-for-setting-up-a-local-workspace). + 1. Fork the JabRef into your GitHub account. + 2. Clone your forked repository on your local machine. +3. **Create a new branch** (such as `fix-for-issue-121`). Be sure to create a **separate branch** for each improvement you implement. +4. Do your work on the **new branch - not the master branch.** Refer to our [code howtos](https://github.com/JabRef/jabref/wiki/Code-Howtos) if you have questions about your implementation. +5. Create a pull request. For an overview of pull requests, take a look at GitHub's [pull request help documentation](https://help.github.com/articles/about-pull-requests/). + +In case you have any questions, do not hesitate to write one of our [JabRef developers](https://github.com/orgs/JabRef/teams/developers) an email. We should also be online at [gitter](https://gitter.im/JabRef/jabref). ## Formal requirements for a pull request diff --git a/LICENSE.md b/LICENSE.md index 150d62db659..592eef7d390 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright © 2003-2018 [JabRef Authors](https://github.com/JabRef/jabref/blob/master/AUTHORS) +Copyright © 2003-2019 [JabRef Authors](https://github.com/JabRef/jabref/blob/master/AUTHORS) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index d0a9efc35f7..da4f8b31e64 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,21 @@ [![Build Status](https://travis-ci.org/JabRef/jabref.svg?branch=master)](https://travis-ci.org/JabRef/jabref) [![codecov.io](https://codecov.io/github/JabRef/jabref/coverage.svg?branch=master)](https://codecov.io/github/JabRef/jabref?branch=master) [![Donation](https://img.shields.io/badge/donate%20to-jabref-orange.svg)](https://donations.jabref.org) +[![Crowdin](https://d322cqt584bo4o.cloudfront.net/jabref/localized.svg)](https://crowdin.com/project/jabref) JabRef is an open-source, cross-platform citation and reference management tool licensed under the [MIT license](https://tldrlegal.com/license/mit-license). 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-4-0-MainTable.png) +## Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [Bug Reports, Suggestions, Other Feedback](#bug-reports-suggestions-other-feedback) +- [Contributing](#contributing) +- [Acknowledgements](#acknowledgements) / [License](#license) + ## 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. diff --git a/build.gradle b/build.gradle index 1f1847f2b2a..6ce97a88ba8 100644 --- a/build.gradle +++ b/build.gradle @@ -16,13 +16,13 @@ buildscript { } plugins { - id 'com.gradle.build-scan' version '2.3' - id 'com.install4j.gradle' version '7.0.11' - id 'com.github.johnrengelman.shadow' version '5.0.0' - id "com.simonharrer.modernizer" version '1.6.0-1' + id 'com.gradle.build-scan' version '2.4.1' + id 'com.install4j.gradle' version '7.0.12' + id 'com.github.johnrengelman.shadow' version '5.1.0' + id "com.simonharrer.modernizer" version '1.8.0-1' id 'me.champeau.gradle.jmh' version '0.4.8' - id 'net.ltgt.errorprone' version '0.8' - id 'com.github.ben-manes.versions' version '0.21.0' + id 'net.ltgt.errorprone' version '0.8.1' + id 'com.github.ben-manes.versions' version '0.22.0' } // use the gradle build scan feature: https://scans.gradle.com/get-started @@ -90,14 +90,14 @@ dependencies { // Include all jar-files in the 'lib' folder as dependencies compile fileTree(dir: 'lib', includes: ['*.jar']) - compile 'org.apache.pdfbox:pdfbox:2.0.15' - compile 'org.apache.pdfbox:fontbox:2.0.15' - compile 'org.apache.pdfbox:xmpbox:2.0.15' + compile 'org.apache.pdfbox:pdfbox:2.0.16' + compile 'org.apache.pdfbox:fontbox:2.0.16' + compile 'org.apache.pdfbox:xmpbox:2.0.16' - compile group: 'org.apache.tika', name: 'tika-core', version: '1.20' + compile group: 'org.apache.tika', name: 'tika-parsers', version: '1.22' // required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635 - compile 'org.bouncycastle:bcprov-jdk15on:1.61' + compile 'org.bouncycastle:bcprov-jdk15on:1.62' compile 'commons-cli:commons-cli:1.4' @@ -115,13 +115,11 @@ dependencies { antlr4 'org.antlr:antlr4:4.7.2' compile 'org.antlr:antlr4-runtime:4.7.2' - compile 'mysql:mysql-connector-java:8.0.16' + compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.4.3' - compile 'org.postgresql:postgresql:42.2.5' + compile 'org.postgresql:postgresql:42.2.6' - compile 'net.java.dev.glazedlists:glazedlists_java15:1.9.1' - - compile 'com.google.guava:guava:27.1-jre' + compile 'com.google.guava:guava:28.0-jre' // JavaFX stuff compile 'de.jensd:fontawesomefx-commons:8.15' @@ -130,23 +128,23 @@ dependencies { compile 'de.saxsys:mvvmfx:1.8.0' compile 'org.fxmisc.easybind:easybind:1.0.3' compile 'org.fxmisc.flowless:flowless:0.6.1' - compile 'org.fxmisc.richtext:richtextfx:0.10.0' + compile 'org.fxmisc.richtext:richtextfx:0.10.1' compile 'com.sibvisions.external.jvxfx:dndtabpane:0.1' compile 'javax.inject:javax.inject:1' - compile 'com.jfoenix:jfoenix:8.0.8' + compile 'com.jfoenix:jfoenix:8.0.9' // Cannot be updated to 9.*.* until Jabref works with Java 9 - compile 'org.controlsfx:controlsfx:8.40.15-SNAPSHOT' + compile 'org.controlsfx:controlsfx:8.40.16-SNAPSHOT' compile 'org.jsoup:jsoup:1.12.1' compile 'com.mashape.unirest:unirest-java:1.4.9' // >1.8.0-beta is required for java 9 compatibility - compile 'org.slf4j:slf4j-api:1.8.0-beta4' - compile 'org.apache.logging.log4j:log4j-slf4j18-impl:2.11.2' - compile 'org.apache.logging.log4j:log4j-jcl:2.11.2' - compile 'org.apache.logging.log4j:log4j-api:2.11.2' - compile 'org.apache.logging.log4j:log4j-core:2.11.2' + compile 'org.slf4j:slf4j-api:2.0.0-alpha0' + compile 'org.apache.logging.log4j:log4j-slf4j18-impl:2.12.1' + compile 'org.apache.logging.log4j:log4j-jcl:2.12.1' + compile 'org.apache.logging.log4j:log4j-api:2.12.1' + compile 'org.apache.logging.log4j:log4j-core:2.12.1' compile 'de.undercouch:citeproc-java:1.0.1' @@ -154,26 +152,26 @@ dependencies { errorproneJavac 'com.google.errorprone:javac:1.8.0-u20' - compile group: 'com.microsoft.azure', name: 'applicationinsights-core', version: '2.3.1' - compile group: 'com.microsoft.azure', name: 'applicationinsights-logging-log4j2', version: '2.3.1' + compile group: 'com.microsoft.azure', name: 'applicationinsights-core', version: '2.4.1' + compile group: 'com.microsoft.azure', name: 'applicationinsights-logging-log4j2', version: '2.4.1' - testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.4.2' - testCompile 'org.junit.platform:junit-platform-launcher:1.4.2' + testImplementation 'org.junit.jupiter:junit-jupiter:5.5.1' + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.5.1' + testCompile 'org.junit.platform:junit-platform-launcher:1.5.1' - testRuntime 'org.apache.logging.log4j:log4j-core:2.11.1' - testRuntime 'org.apache.logging.log4j:log4j-jul:2.11.2' - testCompile 'org.mockito:mockito-core:2.27.0' - testCompile 'com.github.tomakehurst:wiremock:2.23.2' + testRuntime 'org.apache.logging.log4j:log4j-core:2.12.0' + testRuntime 'org.apache.logging.log4j:log4j-jul:2.12.1' + testCompile 'org.mockito:mockito-core:3.0.0' + testCompile 'com.github.tomakehurst:wiremock:2.24.1' testCompile 'org.reflections:reflections:0.9.11' - testCompile 'org.xmlunit:xmlunit-core:2.6.2' - testCompile 'org.xmlunit:xmlunit-matchers:2.6.2' - testRuntime 'com.tngtech.archunit:archunit-junit5-engine:0.10.2' - testCompile 'com.tngtech.archunit:archunit-junit5-api:0.10.2' + testCompile 'org.xmlunit:xmlunit-core:2.6.3' + testCompile 'org.xmlunit:xmlunit-matchers:2.6.3' + testRuntime 'com.tngtech.archunit:archunit-junit5-engine:0.11.0' + testCompile 'com.tngtech.archunit:archunit-junit5-api:0.11.0' testCompile "org.testfx:testfx-core:4.0.+" testCompile "org.testfx:testfx-junit5:4.0.+" - checkstyle 'com.puppycrawl.tools:checkstyle:8.20' + checkstyle 'com.puppycrawl.tools:checkstyle:8.23' xjc 'com.sun.xml.bind:jaxb-xjc:2.2.4-1' jython 'org.python:jython-standalone:2.7.1' } @@ -190,8 +188,11 @@ dependencyUpdates { dependencyUpdates.resolutionStrategy = { componentSelection { rules -> rules.all { ComponentSelection selection -> - if (selection.candidate.version ==~ /[0-9].*SNAPSHOT/) { - selection.reject("Ignore SNAPSHOT releases") + boolean rejected = ['alpha', 'snapshot', 'beta', 'rc', 'cr', 'm', 'preview', 'b', 'ea'].any { qualifier -> + selection.candidate.version ==~ /(?i).*[.-]$qualifier[.\d-+]*/ + } + if (rejected) { + selection.reject('Release candidate') } } rules.withModule("org.controlsfx:controlsfx") { ComponentSelection selection -> @@ -200,7 +201,7 @@ dependencyUpdates.resolutionStrategy = { } } rules.withModule("com.github.tomtung:latex2unicode_2.12") { ComponentSelection selection -> - if (selection.candidate.version ==~ /0.2.[3,4]/) { + if (selection.candidate.version ==~ /0.2.*/) { // Reject version higher than 2.0.2. see https://github.com/JabRef/jabref/pull/3781 selection.reject("Cannot be updated to 0.2.4 until JabRef is prepared for it") } @@ -433,6 +434,7 @@ modernizer { shadowJar { transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer) classifier 'fat' + zip64 true } /* diff --git a/docs/adr/0000-use-markdown-architectural-decision-records.md b/docs/adr/0000-use-markdown-architectural-decision-records.md index be7d1ed5fa8..1aab9e567f7 100644 --- a/docs/adr/0000-use-markdown-architectural-decision-records.md +++ b/docs/adr/0000-use-markdown-architectural-decision-records.md @@ -7,19 +7,20 @@ Which format and structure should these records follow? ## Considered Options -* [MADR](https://adr.github.io/madr/) 2.0.3 - The Markdown Architectural Decision Records -* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) - The first incarnation of the term "ADR" -* [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) - The Y-Statements +* [MADR](https://adr.github.io/madr/) 2.1.2 – The Markdown Architectural Decision Records +* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) – The first incarnation of the term "ADR" +* [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) – The Y-Statements * Other templates listed at -* Formless - No conventions for file format and structure +* Formless – No conventions for file format and structure ## Decision Outcome -Chosen option: "MADR 2.0.3", because +Chosen option: "MADR 2.1.2", because + * Implicit assumptions should be made explicit. Design documentation is important to enable people understanding the decisions later on. See also [A rational design process: How and why to fake it](https://doi.org/10.1109/TSE.1986.6312940). * The MADR format is lean and fits our development style. * The MADR structure is comprehensible and facilitates usage & maintenance. * The MADR project is vivid. -* Version 2.0.3 is the latest one available when starting to document ADRs. +* Version 2.1.2 is the latest one available when starting to document ADRs. diff --git a/docs/adr/0004-use-mariadb-connector.md b/docs/adr/0004-use-mariadb-connector.md new file mode 100644 index 00000000000..413364bfe35 --- /dev/null +++ b/docs/adr/0004-use-mariadb-connector.md @@ -0,0 +1,34 @@ +# Use MariaDB Connector + +## Context and Problem Statement + +JabRef needs to connect to a MySQL database. +See [Shared SQL Database](https://help.jabref.org/en/SQLDatabase) for more information. + +## Considered Options + +* Use MariaDB Connector +* Use MySQL Connector + +Other alternatives are listed at . + +## Decision Outcome + +Chosen option: "Use MariaDB Connector", because comes out best (see below). + +## Pros and Cons of the Options + +### Use MariaDB Connector + +The [MariaDB Connector](https://mariadb.com/kb/en/library/about-mariadb-connector-j/) is a LGPL-licensed JDBC driver to connect to MySQL and MariaDB. + +* Good, because can be used as drop-in replacement for MySQL connectopr + +### Use MySQL Connector + +The [MySQL Connector](https://www.mysql.com/de/products/connector/) is distributed by Oracle and licensed under GPL-2. Source: . +Oracle added the [Universal FOSS Exception, Version 1.0](https://oss.oracle.com/licenses/universal-foss-exception/) to it, which seems to limit the effects of GPL. +More information on the FOSS Exception are available at . + +* 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/index.md b/docs/adr/index.md index c44730123e6..7bbc5b8c4fc 100644 --- a/docs/adr/index.md +++ b/docs/adr/index.md @@ -8,6 +8,7 @@ This log lists the architectural decisions for JabRef. - [ADR-0001](0001-use-crowdin-for-translations.md) - Use Crowdin for translations - [ADR-0002](0002-use-slf4j-for-logging.md) - Use slf4j together with log4j2 for logging - [ADR-0003](0003-use-gradle-as-build-tool.md) - Use Gradle as build tool +- [ADR-0004](0004-use-mariadb-connector.md) - Use MariaDB Connector diff --git a/docs/adr/template.md b/docs/adr/template.md index e4659b49b2b..25696bbe7c8 100644 --- a/docs/adr/template.md +++ b/docs/adr/template.md @@ -1,6 +1,6 @@ # [short title of solved problem and solution] -* Status: [accepted | superseeded by [ADR-0005](0005-example.md) | deprecated | …] +* Status: [proposed | rejected | accepted | deprecated | … | superseded by [ADR-0005](0005-example.md)] * Deciders: [list everyone involved in the decision] * Date: [YYYY-MM-DD when the decision was last updated] @@ -27,11 +27,13 @@ Technical Story: [description | ticket/issue URL] Chosen option: "[option 1]", because [justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force force | … | comes out best (see below)]. -Positive Consequences: +### Positive Consequences + * [e.g., improvement of quality attribute satisfaction, follow-up decisions required, …] * … -Negative consequences: +### Negative Consequences + * [e.g., compromising quality attribute, follow-up decisions required, …] * … diff --git a/external-libraries.txt b/external-libraries.txt index e036e8aa3de..107ae83f6e4 100644 --- a/external-libraries.txt +++ b/external-libraries.txt @@ -110,11 +110,6 @@ Project: java-diff-utils URL: https://github.com/java-diff-utils/java-diff-utils License: Apache-1.1 -Id: mysql:mysql-connector-java -Project: MySQL Connector/J -URL: http://www.mysql.de/downloads/connector/j/ -License: GPL-2.0 and Oracle's FOSS License Exception (http://www.mysql.com/about/legal/licensing/foss-exception/) allowing GPLv3 - Id: net.java.dev.glazedlists:glazedlists_java15 Project: Glazed Lists URL: http://www.glazedlists.com/ @@ -195,6 +190,11 @@ Project: jsoup URL: https://github.com/jhy/jsoup/ License: MIT +Id: org.mariadb.jdbc:mariadb-java-client +Project: MariaDB Java Client +URL: https://mariadb.com/kb/en/library/about-mariadb-connector-j/ +License: LGPL-2.1-or-later + Id: org.openoffice:juh Project: OpenOffice.org URL: http://www.openoffice.org/api/SDK diff --git a/jabref.install4j b/jabref.install4j index 08da26fd0a2..53b83c0d3bc 100644 --- a/jabref.install4j +++ b/jabref.install4j @@ -1,5 +1,5 @@ - + diff --git a/scripts/download-install4j-and-jres.sh b/scripts/download-install4j-and-jres.sh index cdd5aee3b20..4368ef31012 100755 --- a/scripts/download-install4j-and-jres.sh +++ b/scripts/download-install4j-and-jres.sh @@ -5,7 +5,7 @@ if [ ! -d ~/downloads ]; then mkdir ~/downloads fi cd ~/downloads -wget --quiet -nc --show-progress http://download-keycdn.ej-technologies.com/install4j/install4j_unix_7_0_8.tar.gz +wget --quiet -nc --show-progress http://download-keycdn.ej-technologies.com/install4j/install4j_unix_7_0_11.tar.gz # fetch JREs if [ ! -d ~/.install4j7/jres ]; then diff --git a/scripts/extract-install4j.sh b/scripts/extract-install4j.sh index 9e960280b81..74b703b2981 100755 --- a/scripts/extract-install4j.sh +++ b/scripts/extract-install4j.sh @@ -1,4 +1,4 @@ #!/bin/bash -tar -xf ~/downloads/install4j_unix_7_0_8.tar.gz +tar -xf ~/downloads/install4j_unix_7_0_11.tar.gz # fix directory name (until install4j 6.1.5 it was install4j6 -mv install4j7.0.8 install4j7 +mv install4j7.0.11 install4j7 diff --git a/src/jmh/java/org/jabref/benchmarks/Benchmarks.java b/src/jmh/java/org/jabref/benchmarks/Benchmarks.java index a7316584eee..d0a0704c5f6 100644 --- a/src/jmh/java/org/jabref/benchmarks/Benchmarks.java +++ b/src/jmh/java/org/jabref/benchmarks/Benchmarks.java @@ -22,6 +22,9 @@ import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.database.BibDatabaseModeDetection; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BibEntryTypesManager; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.field.UnknownField; import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.KeywordGroup; import org.jabref.model.groups.WordKeywordGroup; @@ -54,12 +57,12 @@ public void init() throws Exception { for (int i = 0; i < 1000; i++) { BibEntry entry = new BibEntry(); entry.setCiteKey("id" + i); - entry.setField("title", "This is my title " + i); - entry.setField("author", "Firstname Lastname and FirstnameA LastnameA and FirstnameB LastnameB" + i); - entry.setField("journal", "Journal Title " + i); - entry.setField("keyword", "testkeyword"); - entry.setField("year", "1" + i); - entry.setField("rnd", "2" + randomizer.nextInt()); + entry.setField(StandardField.TITLE, "This is my title " + i); + entry.setField(StandardField.AUTHOR, "Firstname Lastname and FirstnameA LastnameA and FirstnameB LastnameB" + i); + entry.setField(StandardField.JOURNAL, "Journal Title " + i); + entry.setField(StandardField.KEYWORDS, "testkeyword"); + entry.setField(StandardField.YEAR, "1" + i); + entry.setField(new UnknownField("rnd"), "2" + randomizer.nextInt()); database.insertEntry(entry); } @@ -72,7 +75,7 @@ public void init() throws Exception { private StringWriter getOutputWriter() throws IOException { StringWriter outputWriter = new StringWriter(); - BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter(outputWriter, mock(SavePreferences.class)); + BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter(outputWriter, mock(SavePreferences.class), new BibEntryTypesManager()); databaseWriter.savePartOfDatabase( new BibDatabaseContext(database, new MetaData(), new Defaults()), database.getEntries()); return outputWriter; @@ -128,7 +131,7 @@ public String htmlToLatexConversion() { @Benchmark public boolean keywordGroupContains() { - KeywordGroup group = new WordKeywordGroup("testGroup", GroupHierarchyType.INDEPENDENT, "keyword", "testkeyword", false, ',', false); + KeywordGroup group = new WordKeywordGroup("testGroup", GroupHierarchyType.INDEPENDENT, StandardField.KEYWORDS, "testkeyword", false, ',', false); return group.containsAll(database.getEntries()); } diff --git a/src/main/java/org/jabref/Globals.java b/src/main/java/org/jabref/Globals.java index 1a5cc0ee385..71466ee47c7 100644 --- a/src/main/java/org/jabref/Globals.java +++ b/src/main/java/org/jabref/Globals.java @@ -1,6 +1,7 @@ package org.jabref; import java.awt.GraphicsEnvironment; +import java.io.IOException; import java.util.Optional; import java.util.UUID; @@ -20,10 +21,12 @@ import org.jabref.logic.protectedterms.ProtectedTermsLoader; import org.jabref.logic.remote.server.RemoteListenerServerLifecycle; import org.jabref.logic.util.BuildInfo; +import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.JabRefPreferences; import com.google.common.base.StandardSystemProperty; +import com.mashape.unirest.http.Unirest; import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.internal.shutdown.SDKShutdownActivity; @@ -59,6 +62,7 @@ public class Globals { public static StateManager stateManager = new StateManager(); public static ExporterFactory exportFactory; public static CountingUndoManager undoManager = new CountingUndoManager(); + public static BibEntryTypesManager entryTypesManager = new BibEntryTypesManager(); // Key binding preferences private static KeyBindingRepository keyBindingRepository; private static DefaultFileUpdateMonitor fileUpdateMonitor; @@ -125,6 +129,9 @@ public static void shutdownThreadPools() { public static void stopBackgroundTasks() { stopTelemetryClient(); + try { + Unirest.shutdown(); + } catch (IOException ignore) { } } public static Optional getTelemetryClient() { diff --git a/src/main/java/org/jabref/JabRefMain.java b/src/main/java/org/jabref/JabRefMain.java index 62758e9c9f0..b33849356b5 100644 --- a/src/main/java/org/jabref/JabRefMain.java +++ b/src/main/java/org/jabref/JabRefMain.java @@ -22,9 +22,7 @@ import org.jabref.logic.util.JavaVersion; import org.jabref.logic.util.OS; import org.jabref.migrations.PreferencesMigrations; -import org.jabref.model.EntryTypes; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.InternalBibtexFields; import org.jabref.preferences.JabRefPreferences; import org.slf4j.Logger; @@ -153,21 +151,14 @@ private static boolean handleMultipleAppInstances(String[] args) { } private static void applyPreferences(JabRefPreferences preferences) { - // Update handling of special fields based on preferences - InternalBibtexFields.updateSpecialFields(Globals.prefs.getBoolean(JabRefPreferences.SERIALIZESPECIALFIELDS)); - // Update name of the time stamp field based on preferences - InternalBibtexFields.updateTimeStampField(Globals.prefs.getTimestampPreferences().getTimestampField()); - // Update which fields should be treated as numeric, based on preferences: - InternalBibtexFields.setNumericFields(Globals.prefs.getStringList(JabRefPreferences.NUMERIC_FIELDS)); - // Read list(s) of journal names and abbreviations Globals.journalAbbreviationLoader = new JournalAbbreviationLoader(); // Build list of Import and Export formats Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(), Globals.prefs.getXMPPreferences(), Globals.getFileUpdateMonitor()); - EntryTypes.loadCustomEntryTypes(preferences.loadCustomEntryTypes(BibDatabaseMode.BIBTEX), - preferences.loadCustomEntryTypes(BibDatabaseMode.BIBLATEX)); + Globals.entryTypesManager.addCustomizedEntryTypes(preferences.loadBibEntryTypes(BibDatabaseMode.BIBTEX), + preferences.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); Globals.exportFactory = Globals.prefs.getExporterFactory(Globals.journalAbbreviationLoader); // Initialize protected terms loader diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index 56a4de65bde..4fd9a9f2b51 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -44,7 +44,6 @@ import org.jabref.logic.util.OS; import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.Defaults; -import org.jabref.model.EntryTypes; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; @@ -391,7 +390,7 @@ private void saveDatabase(BibDatabase newBase, String subName) { System.out.println(Localization.lang("Saving") + ": " + subName); SavePreferences prefs = Globals.prefs.loadForSaveFromPreferences(); AtomicFileWriter fileWriter = new AtomicFileWriter(Paths.get(subName), prefs.getEncoding()); - BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(fileWriter, prefs); + BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(fileWriter, prefs, Globals.entryTypesManager); Defaults defaults = new Defaults(Globals.prefs.getDefaultBibDatabaseMode()); databaseWriter.saveDatabase(new BibDatabaseContext(newBase, defaults)); @@ -458,8 +457,8 @@ private void exportFile(List loaded, String[] data) { private void importPreferences() { try { Globals.prefs.importPreferences(cli.getPreferencesImport()); - EntryTypes.loadCustomEntryTypes(Globals.prefs.loadCustomEntryTypes(BibDatabaseMode.BIBTEX), - Globals.prefs.loadCustomEntryTypes(BibDatabaseMode.BIBLATEX)); + Globals.entryTypesManager.addCustomizedEntryTypes(Globals.prefs.loadBibEntryTypes(BibDatabaseMode.BIBTEX), + Globals.prefs.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); List customExporters = Globals.prefs.getCustomExportFormats(Globals.journalAbbreviationLoader); LayoutFormatterPreferences layoutPreferences = Globals.prefs .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader); diff --git a/src/main/java/org/jabref/cli/CrossrefFetcherEvaluator.java b/src/main/java/org/jabref/cli/CrossrefFetcherEvaluator.java index 2713698933d..69641fa60c7 100644 --- a/src/main/java/org/jabref/cli/CrossrefFetcherEvaluator.java +++ b/src/main/java/org/jabref/cli/CrossrefFetcherEvaluator.java @@ -16,7 +16,7 @@ import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.identifier.DOI; import org.jabref.preferences.JabRefPreferences; @@ -53,7 +53,7 @@ public static void main(String[] args) throws IOException, InterruptedException @Override public void run() { - Optional origDOI = entry.getField(FieldName.DOI).flatMap(DOI::parse); + Optional origDOI = entry.getField(StandardField.DOI).flatMap(DOI::parse); if (origDOI.isPresent()) { dois.incrementAndGet(); try { diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index 83459c97e01..dc2edfe8984 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -4,7 +4,6 @@ import org.jabref.Globals; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabaseMode; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; @@ -17,27 +16,25 @@ public class JabRefCLI { + private static final int WIDTH = 100; // Number of characters per line private static final Logger LOGGER = LoggerFactory.getLogger(JabRefCLI.class); private final CommandLine cl; private List leftOver; public JabRefCLI(String[] args) { - Options options = getOptions(); - try { this.cl = new DefaultParser().parse(options, args); this.leftOver = cl.getArgList(); } catch (ParseException e) { LOGGER.warn("Problem parsing arguments", e); - this.printUsage(); throw new RuntimeException(); } } public static String getExportMatchesSyntax() { - return String.format("[%s]searchTerm,outputFile: %s[,%s]", + return String.format("[%s]searchTerm,outputFile:%s[,%s]", Localization.lang("field"), Localization.lang("file"), Localization.lang("exportFormat")); @@ -147,104 +144,97 @@ public String getExportMatches() { return cl.getOptionValue("exportMatches"); } - public boolean isGenerateBibtexKeys() { return cl.hasOption("generateBibtexKeys"); } + public boolean isGenerateBibtexKeys() { + return cl.hasOption("generateBibtexKeys"); + } - public boolean isAutomaticallySetFileLinks() { return cl.hasOption("automaticallySetFileLinks"); } + public boolean isAutomaticallySetFileLinks() { + return cl.hasOption("automaticallySetFileLinks"); + } private Options getOptions() { Options options = new Options(); // boolean options - options.addOption("v", "version", false, Localization.lang("Display version")); - options.addOption("n", "nogui", false, Localization.lang("No GUI. Only process command line options.")); 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("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")); // The "-console" option is handled by the install4j launcher - options.addOption(null, "console", false, Localization.lang("Show console output (only necessary when the launcher is used)")); + options.addOption(null, "console", false, Localization.lang("Show console output (only when the launcher is used)")); options.addOption(Option.builder("i"). longOpt("import"). - desc(String.format("%s: %s[,import format]", Localization.lang("Import file"), - Localization.lang("filename"))). + desc(String.format("%s: '%s'", Localization.lang("Import file"), "-i library.bib")). hasArg(). - argName("FILE").build()); + argName("FILE[,FORMAT]"). + build()); - options.addOption( - Option.builder("ib") - .longOpt("importBibtex") - .desc(String.format("%s: %s[,importBibtex bibtexString]", Localization.lang("Import") + " " + BibDatabaseMode.BIBTEX.getFormattedName(), Localization.lang("filename"))) - .hasArg() - .argName("FILE") - .build()); + options.addOption(Option.builder(). + longOpt("importToOpen"). + desc(Localization.lang("Same as --import, but will be imported to the opened tab")). + hasArg(). + argName("FILE[,FORMAT]"). + build()); - options.addOption(Option.builder("o"). - longOpt("output"). - desc(String.format("%s: %s[,export format]", Localization.lang("Output or export file"), - Localization.lang("filename"))). + options.addOption(Option.builder("ib"). + longOpt("importBibtex"). + desc(String.format("%s: '%s'", Localization.lang("Import BibTeX"), "-ib @article{entry}")). hasArg(). - argName("FILE"). + argName("BIBTEXT_STRING"). build()); - options.addOption(Option.builder("x"). - longOpt("prexp"). - desc(Localization.lang("Export preferences to file")). + options.addOption(Option.builder("o"). + longOpt("output"). + desc(String.format("%s: '%s'", Localization.lang("Export an input to a file"), "-i db.bib -o db.htm,html")). hasArg(). - argName("FILE"). + argName("FILE[,FORMAT]"). build()); - options.addOption(Option.builder("p"). - longOpt("primp"). - desc(Localization.lang("Import preferences from file")). + options.addOption(Option.builder("m"). + longOpt("exportMatches"). + desc(String.format("%s: '%s'", Localization.lang("Matching"), "-i db.bib -m author=Newton,search.htm,html")). hasArg(). - argName("FILE"). + argName("QUERY,FILE[,FORMAT]"). build()); - options.addOption(Option.builder("d"). - longOpt("prdef"). - desc(Localization.lang("Reset preferences (key1,key2,... or 'all')")). + + options.addOption(Option.builder("f"). + longOpt("fetch"). + desc(String.format("%s: '%s'", Localization.lang("Run fetcher"), "-f Medline/PubMed:cancer")). hasArg(). - argName("FILE"). + argName("FETCHER:QUERY"). build()); options.addOption(Option.builder("a"). longOpt("aux"). - desc(String.format("%s: %s[.aux],%s[.bib]", Localization.lang("Sublibrary from AUX"), - Localization.lang("file"), - Localization.lang("new"))). + desc(String.format("%s: '%s'", Localization.lang("Sublibrary from AUX to BibTeX"), "-a thesis.aux,new.bib")). hasArg(). - argName("FILE"). + argName("FILE[.aux],FILE[.bib] FILE"). build()); - options.addOption(Option.builder(). - longOpt("importToOpen"). - desc(Localization.lang("Import to open tab")). + options.addOption(Option.builder("x"). + longOpt("prexp"). + desc(String.format("%s: '%s'", Localization.lang("Export preferences to a file"), "-x prefs.xml")). hasArg(). - argName("FILE"). + argName("[FILE]"). build()); - options.addOption(Option.builder("f"). - longOpt("fetch"). - desc(Localization.lang("Run fetcher, e.g. \"--fetch=Medline:cancer\"")). + options.addOption(Option.builder("p"). + longOpt("primp"). + desc(String.format("%s: '%s'", Localization.lang("Import preferences from a file"), "-p prefs.xml")). hasArg(). - argName("FILE"). + argName("[FILE]"). build()); - options.addOption(Option.builder("m"). - longOpt("exportMatches"). - desc(JabRefCLI.getExportMatchesSyntax()). + options.addOption(Option.builder("d"). + longOpt("prdef"). + desc(String.format("%s: '%s'", Localization.lang("Reset preferences"), "-d mainFontSize,newline' or '-d all")). hasArg(). - argName("FILE"). - build()); - - options.addOption(Option.builder("g"). - longOpt("generateBibtexKeys"). - desc(Localization.lang("Regenerate all keys for the entries in a BibTeX file")) - .build()); - - options.addOption(Option.builder("asfl"). - longOpt("automaticallySetFileLinks"). - desc(Localization.lang("Automatically set file links")). + argName("KEY1[,KEY2][,KEYn] | all"). build()); return options; @@ -266,7 +256,7 @@ public void printUsage() { String footer = '\n' + importFormatsList + outFormatsList + "\nPlease report issues at https://github.com/JabRef/jabref/issues."; HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("jabref [OPTIONS] [BIBTEX_FILE]\n\nOptions:", header, getOptions(), footer, true); + formatter.printHelp(WIDTH, "jabref [OPTIONS] [BIBTEX_FILE]\n\nOptions:", header, getOptions(), footer, true); } private String getVersionInfo() { diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 642fe8dcf88..5236268d894 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -1015,6 +1015,11 @@ We want to have a look that matches our icons in the tool-bar */ -fx-fill: -jr-warn; } +.warning-message { + -fx-fill: -jr-error; + -fx-text-fill: -jr-error; +} + .error-icon { -fx-text-fill: -jr-error; -fx-fill: -jr-error; @@ -1028,7 +1033,20 @@ We want to have a look that matches our icons in the tool-bar */ -fx-background-color: -jr-error; } +.titleHeader { + -fx-font-size: 150%; + -fx-padding: 0em 0em 0.5em 0em; +} + .sectionHeader { - -fx-font-size: 1.5em; - -fx-padding: 1em 0em 1em 0em; + -fx-font-size: 130%; + -fx-padding: 1em 0em 0.2em 0em; +} + +.dialog-pane { + -fx-background-color: -fx-control-inner-background; +} + +.preference-sidepane { + -fx-background-color: -jr-sidepane-background; } diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 932491c4800..cc1902f2212 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.io.StringReader; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -14,7 +13,6 @@ import java.util.Set; import java.util.stream.Collectors; -import javax.swing.SwingUtilities; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; @@ -45,12 +43,8 @@ import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.exporter.WriteXMPAction; import org.jabref.gui.externalfiles.FindFullTextAction; -import org.jabref.gui.externalfiletype.ExternalFileMenuItem; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.gui.filelist.FileListEntry; -import org.jabref.gui.filelist.FileListTableModel; -import org.jabref.gui.icon.JabRefIcon; import org.jabref.gui.importer.actions.AppendDatabaseAction; import org.jabref.gui.journals.AbbreviateAction; import org.jabref.gui.journals.UnabbreviateAction; @@ -59,7 +53,6 @@ import org.jabref.gui.mergeentries.MergeEntriesAction; import org.jabref.gui.mergeentries.MergeWithFetchedEntryAction; import org.jabref.gui.preview.CitationStyleToClipboardWorker; -import org.jabref.gui.preview.PreviewPanel; import org.jabref.gui.specialfields.SpecialFieldDatabaseChangeListener; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; import org.jabref.gui.specialfields.SpecialFieldViewModel; @@ -92,13 +85,15 @@ import org.jabref.model.database.shared.DatabaseLocation; import org.jabref.model.database.shared.DatabaseSynchronizer; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.InternalBibtexFields; +import org.jabref.model.entry.FileFieldParser; import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.event.EntryChangedEvent; import org.jabref.model.entry.event.EntryEventSource; -import org.jabref.model.entry.specialfields.SpecialField; -import org.jabref.model.entry.specialfields.SpecialFieldValue; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; +import org.jabref.model.entry.field.SpecialField; +import org.jabref.model.entry.field.SpecialFieldValue; +import org.jabref.model.entry.field.StandardField; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreviewPreferences; @@ -126,7 +121,6 @@ public class BasePanel extends StackPane { // Keeps track of the string dialog if it is open. private final Map actions = new HashMap<>(); private final SidePaneManager sidePaneManager; - private final PreviewPanel preview; private final BasePanelPreferences preferences; private final ExternalFileTypes externalFileTypes; @@ -182,10 +176,7 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); - this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences(), Globals.getFileUpdateMonitor(), dialogService, externalFileTypes, Globals.TASK_EXECUTOR); - - this.preview = new PreviewPanel(getBibDatabaseContext(), this, dialogService, externalFileTypes, Globals.getKeyPrefs(), preferences.getPreviewPreferences()); - frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview); + this.entryEditor = new EntryEditor(this, externalFileTypes); } @Subscribe @@ -268,8 +259,6 @@ private void setupActions() { // The action for copying selected entries. actions.put(Actions.COPY, this::copy); - actions.put(Actions.PRINT_PREVIEW, new PrintPreviewAction()); - actions.put(Actions.CUT, this::cut); actions.put(Actions.DELETE, () -> delete(false)); @@ -342,37 +331,27 @@ private void setupActions() { actions.put(Actions.REPLACE_ALL, () -> (new ReplaceStringAction(this)).execute()); actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getCommand(), - new SpecialFieldViewModel(SpecialField.RELEVANCE, undoManager).getSpecialFieldAction(SpecialField.RELEVANCE.getValues().get(0), frame)); + new SpecialFieldViewModel(SpecialField.RELEVANCE, undoManager).getSpecialFieldAction(SpecialField.RELEVANCE.getValues().get(0), frame)); actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getCommand(), - new SpecialFieldViewModel(SpecialField.QUALITY, undoManager).getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame)); + new SpecialFieldViewModel(SpecialField.QUALITY, undoManager).getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame)); actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getCommand(), - new SpecialFieldViewModel(SpecialField.PRINTED, undoManager).getSpecialFieldAction(SpecialField.PRINTED.getValues().get(0), frame)); + new SpecialFieldViewModel(SpecialField.PRINTED, undoManager).getSpecialFieldAction(SpecialField.PRINTED.getValues().get(0), frame)); for (SpecialFieldValue prio : SpecialField.PRIORITY.getValues()) { actions.put(new SpecialFieldValueViewModel(prio).getCommand(), - new SpecialFieldViewModel(SpecialField.PRIORITY, undoManager).getSpecialFieldAction(prio, this.frame)); + new SpecialFieldViewModel(SpecialField.PRIORITY, undoManager).getSpecialFieldAction(prio, this.frame)); } for (SpecialFieldValue rank : SpecialField.RANKING.getValues()) { actions.put(new SpecialFieldValueViewModel(rank).getCommand(), - new SpecialFieldViewModel(SpecialField.RANKING, undoManager).getSpecialFieldAction(rank, this.frame)); + new SpecialFieldViewModel(SpecialField.RANKING, undoManager).getSpecialFieldAction(rank, this.frame)); } for (SpecialFieldValue status : SpecialField.READ_STATUS.getValues()) { actions.put(new SpecialFieldValueViewModel(status).getCommand(), - new SpecialFieldViewModel(SpecialField.READ_STATUS, undoManager).getSpecialFieldAction(status, this.frame)); + new SpecialFieldViewModel(SpecialField.READ_STATUS, undoManager).getSpecialFieldAction(status, this.frame)); } - actions.put(Actions.TOGGLE_PREVIEW, () -> { - PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences(); - boolean enabled = !previewPreferences.isPreviewPanelEnabled(); - PreviewPreferences newPreviewPreferences = previewPreferences.getBuilder() - .withPreviewPanelEnabled(enabled) - .build(); - Globals.prefs.storePreviewPreferences(newPreviewPreferences); - setPreviewActive(enabled); - }); - actions.put(Actions.NEXT_PREVIEW_STYLE, this::nextPreviewStyle); actions.put(Actions.PREVIOUS_PREVIEW_STYLE, this::previousPreviewStyle); @@ -532,7 +511,7 @@ private void copyKeyAndTitle() { Layout layout; try { layout = new LayoutHelper(sr, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)) - .getLayoutFromText(); + .getLayoutFromText(); } catch (IOException e) { LOGGER.info("Could not get layout", e); return; @@ -574,21 +553,26 @@ private void openExternalFile() { } JabRefExecutorService.INSTANCE.execute(() -> { final BibEntry entry = selectedEntries.get(0); - if (!entry.hasField(FieldName.FILE)) { + if (!entry.hasField(StandardField.FILE)) { // no bibtex field new SearchAndOpenFile(entry, BasePanel.this).searchAndOpen(); return; } - FileListTableModel fileListTableModel = new FileListTableModel(); - entry.getField(FieldName.FILE).ifPresent(fileListTableModel::setContent); - if (fileListTableModel.getRowCount() == 0) { + + List files = new ArrayList<>(); + entry.getField(StandardField.FILE).map(FileFieldParser::parse).ifPresent(files::addAll); + + if (files.isEmpty()) { // content in BibTeX field is not readable new SearchAndOpenFile(entry, BasePanel.this).searchAndOpen(); return; } - FileListEntry flEntry = fileListTableModel.getEntry(0); - ExternalFileMenuItem item = new ExternalFileMenuItem(frame(), "", flEntry.getLink(), flEntry.getType().map(ExternalFileType::getIcon).map(JabRefIcon::getSmallIcon).orElse(null), bibDatabaseContext, flEntry.getType()); - item.doClick(); + LinkedFile flEntry = files.get(0); + try { + JabRefDesktop.openExternalFileAnyFormat(this.getBibDatabaseContext(), flEntry.getLink(), ExternalFileTypes.getInstance().fromLinkedFile(flEntry, true)); + } catch (IOException ex) { + dialogService.showErrorDialogAndWait(ex); + } }); } @@ -638,7 +622,7 @@ public void insertEntry(final BibEntry bibEntry) { // Create an UndoableInsertEntry object. getUndoManager().addEdit(new UndoableInsertEntry(bibDatabaseContext.getDatabase(), bibEntry)); - output(Localization.lang("Added new '%0' entry.", bibEntry.getType())); + output(Localization.lang("Added new '%0' entry.", bibEntry.getType().getDisplayName())); markBaseChanged(); // The database just changed. if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) { @@ -651,11 +635,11 @@ public void insertEntry(final BibEntry bibEntry) { } } - public void editEntryAndFocusField(BibEntry entry, String fieldName) { + public void editEntryAndFocusField(BibEntry entry, Field field) { showAndEdit(entry); Platform.runLater(() -> { // Focus field and entry in main table (async to give entry editor time to load) - entryEditor.setFocusToField(fieldName); + entryEditor.setFocusToField(field); clearAndSelect(entry); }); } @@ -679,7 +663,6 @@ private void createMainTable() { .stream() .findFirst() .ifPresent(entry -> { - preview.setEntry(entry); entryEditor.setEntry(entry); })); @@ -809,16 +792,14 @@ public void updateSearchManager() { } private void instantiateSearchAutoCompleter() { - searchAutoCompleter = new PersonNameSuggestionProvider(InternalBibtexFields.getPersonNameFields()); + searchAutoCompleter = new PersonNameSuggestionProvider(FieldFactory.getPersonNameFields()); for (BibEntry entry : bibDatabaseContext.getDatabase().getEntries()) { searchAutoCompleter.indexEntry(entry); } } private void adjustSplitter() { - if (mode == BasePanelMode.SHOWING_PREVIEW) { - splitPane.setDividerPositions(Globals.prefs.getPreviewPreferences().getPreviewPanelDividerPosition().doubleValue()); - } else if (mode == BasePanelMode.SHOWING_EDITOR) { + if (mode == BasePanelMode.SHOWING_EDITOR) { splitPane.setDividerPositions(preferences.getEntryEditorDividerPosition()); } } @@ -828,9 +809,8 @@ public EntryEditor getEntryEditor() { } /** - * Sets the entry editor as the bottom component in the split pane. If an entry editor already was shown, - * makes sure that the divider doesn't move. Updates the mode to SHOWING_EDITOR. - * Then shows the given entry. + * Sets the entry editor as the bottom component in the split pane. If an entry editor already was shown, makes sure + * that the divider doesn't move. Updates the mode to SHOWING_EDITOR. Then shows the given entry. * * @param entry The entry to edit. */ @@ -845,17 +825,11 @@ public void showAndEdit(BibEntry entry) { } private void showBottomPane(BasePanelMode newMode) { - Node pane; - switch (newMode) { - case SHOWING_PREVIEW: - pane = preview; - break; - case SHOWING_EDITOR: - pane = entryEditor; - break; - default: - throw new UnsupportedOperationException("new mode not recognized: " + newMode.name()); + if (newMode != BasePanelMode.SHOWING_EDITOR) { + throw new UnsupportedOperationException("new mode not recognized: " + newMode.name()); } + Node pane = entryEditor; + if (splitPane.getItems().size() == 2) { splitPane.getItems().set(1, pane); } else { @@ -871,23 +845,6 @@ private void showAndEdit() { } } - /** - * Sets the given preview panel as the bottom component in the split panel. Updates the mode to SHOWING_PREVIEW. - * - * @param entry The entry to show in the preview. - */ - private void showPreview(BibEntry entry) { - showBottomPane(BasePanelMode.SHOWING_PREVIEW); - - preview.setEntry(entry); - } - - private void showPreview() { - if (!mainTable.getSelectedEntries().isEmpty()) { - showPreview(mainTable.getSelectedEntries().get(0)); - } - } - public void nextPreviewStyle() { cyclePreview(Globals.prefs.getPreviewPreferences().getPreviewCyclePosition() + 1); } @@ -902,8 +859,7 @@ private void cyclePreview(int newPosition) { .withPreviewCyclePosition(newPosition) .build(); Globals.prefs.storePreviewPreferences(previewPreferences); - - preview.updateLayout(previewPreferences); + entryEditor.updatePreviewInTabs(previewPreferences); } /** @@ -911,7 +867,7 @@ private void cyclePreview(int newPosition) { */ public void closeBottomPane() { mode = BasePanelMode.SHOWING_NOTHING; - splitPane.getItems().removeAll(entryEditor, preview); + splitPane.getItems().remove(entryEditor); } /** @@ -933,24 +889,17 @@ public void selectNextEntry() { /** * This method is called from an EntryEditor when it should be closed. We relay to the selection listener, which * takes care of the rest. - * - * @param editor The entry editor to close. */ - public void entryEditorClosing(EntryEditor editor) { - if (Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()) { - showPreview(editor.getEntry()); - } else { - closeBottomPane(); - } + public void entryEditorClosing() { + closeBottomPane(); mainTable.requestFocus(); } /** - * Closes the entry editor or preview panel if it is showing the given entry. + * Closes the entry editor if it is showing the given entry. */ - public void ensureNotShowingBottomPanel(BibEntry entry) { - if (((mode == BasePanelMode.SHOWING_EDITOR) && (entryEditor.getEntry() == entry)) - || ((mode == BasePanelMode.SHOWING_PREVIEW))) { + private void ensureNotShowingBottomPanel(BibEntry entry) { + if (((mode == BasePanelMode.SHOWING_EDITOR) && (entryEditor.getEntry() == entry))) { closeBottomPane(); } } @@ -964,16 +913,7 @@ public void updateEntryEditorIfShowing() { public void markBaseChanged() { baseChanged = true; - - if (SwingUtilities.isEventDispatchThread()) { - markBasedChangedInternal(); - } else { - try { - SwingUtilities.invokeAndWait(() -> markBasedChangedInternal()); - } catch (InvocationTargetException | InterruptedException e) { - LOGGER.info("Problem marking database as changed", e); - } - } + markBasedChangedInternal(); } private void markBasedChangedInternal() { @@ -1007,7 +947,7 @@ public BibDatabase getDatabase() { return bibDatabaseContext.getDatabase(); } - public boolean showDeleteConfirmationDialog(int numberOfEntries) { + private boolean showDeleteConfirmationDialog(int numberOfEntries) { if (Globals.prefs.getBoolean(JabRefPreferences.CONFIRM_DELETE)) { String title = Localization.lang("Delete entry"); String message = Localization.lang("Really delete the selected entry?"); @@ -1021,31 +961,26 @@ public boolean showDeleteConfirmationDialog(int numberOfEntries) { } return dialogService.showConfirmationDialogWithOptOutAndWait(title, - message, - okButton, - cancelButton, - Localization.lang("Disable this confirmation dialog"), - optOut -> Globals.prefs.putBoolean(JabRefPreferences.CONFIRM_DELETE, !optOut)); + message, + okButton, + cancelButton, + Localization.lang("Disable this confirmation dialog"), + optOut -> Globals.prefs.putBoolean(JabRefPreferences.CONFIRM_DELETE, !optOut)); } else { return true; } } /** - * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct preference setting. + * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct + * preference setting. */ private void saveDividerLocation(Number position) { if (position == null) { return; } - if (mode == BasePanelMode.SHOWING_PREVIEW) { - PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() - .getBuilder() - .withPreviewPanelDividerPosition(position) - .build(); - Globals.prefs.storePreviewPreferences(previewPreferences); - } else if (mode == BasePanelMode.SHOWING_EDITOR) { + if (mode == BasePanelMode.SHOWING_EDITOR) { preferences.setEntryEditorDividerPosition(position.doubleValue()); } } @@ -1103,14 +1038,6 @@ public String formatOutputMessage(String start, int count) { return String.format("%s %d %s.", start, count, (count > 1 ? Localization.lang("entries") : Localization.lang("entry"))); } - private void setPreviewActive(boolean enabled) { - if (enabled) { - showPreview(); - } else { - preview.close(); - } - } - public CountingUndoManager getUndoManager() { return undoManager; } @@ -1224,7 +1151,7 @@ public void listen(EntryAddedEvent addedEntryEvent) { if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP)) { final List entries = Collections.singletonList(addedEntryEvent.getBibEntry()); Globals.stateManager.getSelectedGroup(bibDatabaseContext).forEach( - selectedGroup -> selectedGroup.addEntriesToGroup(entries)); + selectedGroup -> selectedGroup.addEntriesToGroup(entries)); } } } @@ -1239,8 +1166,7 @@ public void listen(EntryRemovedEvent entryRemovedEvent) { /** * Ensures that the search auto completer is up to date when entries are changed AKA Let the auto completer, if any, - * harvest words from the entry - * Actual methods for autocomplete indexing must run in javafx thread + * harvest words from the entry Actual methods for autocomplete indexing must run in javafx thread */ private class SearchAutoCompleteListener { @@ -1256,8 +1182,8 @@ public void listen(EntryChangedEvent entryChangedEvent) { } /** - * Ensures that the results of the current search are updated when a new entry is inserted into the database - * Actual methods for performing search must run in javafx thread + * Ensures that the results of the current search are updated when a new entry is inserted into the database Actual + * methods for performing search must run in javafx thread */ private class SearchListener { @@ -1301,11 +1227,11 @@ private class OpenURLAction implements BaseAction { public void action() { final List bes = mainTable.getSelectedEntries(); if (bes.size() == 1) { - String field = FieldName.DOI; - Optional link = bes.get(0).getField(FieldName.DOI); - if (bes.get(0).hasField(FieldName.URL)) { - link = bes.get(0).getField(FieldName.URL); - field = FieldName.URL; + Field field = StandardField.DOI; + Optional link = bes.get(0).getField(StandardField.DOI); + if (bes.get(0).hasField(StandardField.URL)) { + link = bes.get(0).getField(StandardField.URL); + field = StandardField.URL; } if (link.isPresent()) { try { @@ -1321,9 +1247,9 @@ public void action() { List files = bes.get(0).getFiles(); Optional linkedFile = files.stream() - .filter(file -> (FieldName.URL.equalsIgnoreCase(file.getFileType()) - || FieldName.PS.equalsIgnoreCase(file.getFileType()) - || FieldName.PDF.equalsIgnoreCase(file.getFileType()))) + .filter(file -> (StandardField.URL.getName().equalsIgnoreCase(file.getFileType()) + || StandardField.PS.getName().equalsIgnoreCase(file.getFileType()) + || StandardField.PDF.getName().equalsIgnoreCase(file.getFileType()))) .findFirst(); if (linkedFile.isPresent()) { @@ -1331,8 +1257,8 @@ public void action() { try { JabRefDesktop.openExternalFileAnyFormat(bibDatabaseContext, - linkedFile.get().getLink(), - ExternalFileTypes.getInstance().fromLinkedFile(linkedFile.get(), true)); + linkedFile.get().getLink(), + ExternalFileTypes.getInstance().fromLinkedFile(linkedFile.get(), true)); output(Localization.lang("External viewer called") + '.'); } catch (IOException e) { @@ -1364,13 +1290,4 @@ public void action() { markChangedOrUnChanged(); } } - - private class PrintPreviewAction implements BaseAction { - - @Override - public void action() { - showPreview(); - preview.print(); - } - } } diff --git a/src/main/java/org/jabref/gui/BasePanelMode.java b/src/main/java/org/jabref/gui/BasePanelMode.java index 2d6cb8daaec..9305439ad2b 100644 --- a/src/main/java/org/jabref/gui/BasePanelMode.java +++ b/src/main/java/org/jabref/gui/BasePanelMode.java @@ -6,7 +6,6 @@ public enum BasePanelMode { SHOWING_NOTHING, - SHOWING_PREVIEW, SHOWING_EDITOR, WILL_SHOW_EDITOR } diff --git a/src/main/java/org/jabref/gui/ClipBoardManager.java b/src/main/java/org/jabref/gui/ClipBoardManager.java index c7c6ce2b9d4..0411f8afd4e 100644 --- a/src/main/java/org/jabref/gui/ClipBoardManager.java +++ b/src/main/java/org/jabref/gui/ClipBoardManager.java @@ -1,6 +1,8 @@ package org.jabref.gui; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -28,13 +30,11 @@ import org.slf4j.LoggerFactory; public class ClipBoardManager { - public static final DataFormat XML = new DataFormat("application/xml"); - + private static final Logger LOGGER = LoggerFactory.getLogger(ClipBoardManager.class); private final Clipboard clipboard; - private final ImportFormatReader importFormatReader; public ClipBoardManager() { @@ -63,9 +63,8 @@ public String getContents() { String result = clipboard.getString(); if (result == null) { return ""; - } else { - return result; } + return result; } public void setHtmlContent(String html) { @@ -82,47 +81,62 @@ public void setContent(String string) { public void setContent(List entries) throws IOException { final ClipboardContent content = new ClipboardContent(); - BibEntryWriter writer = new BibEntryWriter(new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false); + BibEntryWriter writer = new BibEntryWriter(new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), Globals.entryTypesManager); String serializedEntries = writer.serializeAll(entries, BibDatabaseMode.BIBTEX); content.put(DragAndDropDataFormats.ENTRIES, serializedEntries); content.putString(serializedEntries); clipboard.setContent(content); } - public List extractEntries() { + public List extractData() { Object entries = clipboard.getContent(DragAndDropDataFormats.ENTRIES); + if (entries == null) { + return handleStringData(clipboard.getString()); + } + return handleBibTeXData((String) entries); + } + + private List handleBibTeXData(String entries) { BibtexParser parser = new BibtexParser(Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor()); - if (entries != null) { - // We have determined that the clipboard data is a set of entries (serialized as a string). - try { - return parser.parseEntries((String) entries); - } catch (ParseException ex) { - LOGGER.error("Could not paste", ex); - } - } else { - String data = clipboard.getString(); - if (data != null) { - try { - // fetch from doi - Optional doi = DOI.parse(data); - if (doi.isPresent()) { - LOGGER.info("Found DOI in clipboard"); - Optional entry = new DoiFetcher(Globals.prefs.getImportFormatPreferences()).performSearchById(doi.get().getDOI()); - return OptionalUtil.toList(entry); - } else { - try { - UnknownFormatImport unknownFormatImport = importFormatReader.importUnknownFormat(data); - return unknownFormatImport.parserResult.getDatabase().getEntries(); - } catch (ImportException e) { - // import failed and result will be empty - } - } - } catch (FetcherException ex) { - LOGGER.error("Error while fetching", ex); - } - } + try { + return parser.parseEntries(new ByteArrayInputStream(entries.getBytes(StandardCharsets.UTF_8))); + } catch (ParseException ex) { + LOGGER.error("Could not paste", ex); + return Collections.emptyList(); + } + } + + private List handleStringData(String data) { + if (data == null || data.isEmpty()) { + return Collections.emptyList(); + } + + Optional doi = DOI.parse(data); + if (doi.isPresent()) { + return fetchByDOI(doi.get()); + } + + return tryImportFormats(data); + } + + private List tryImportFormats(String data) { + try { + UnknownFormatImport unknownFormatImport = importFormatReader.importUnknownFormat(data); + return unknownFormatImport.parserResult.getDatabase().getEntries(); + } catch (ImportException ignored) { + return Collections.emptyList(); + } + } + + private List fetchByDOI(DOI doi) { + LOGGER.info("Found DOI in clipboard"); + try { + Optional entry = new DoiFetcher(Globals.prefs.getImportFormatPreferences()).performSearchById(doi.getDOI()); + return OptionalUtil.toList(entry); + } catch (FetcherException ex) { + LOGGER.error("Error while fetching", ex); + return Collections.emptyList(); } - return Collections.emptyList(); } } diff --git a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java index 8776ecaca3f..82f3e8606ac 100644 --- a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java +++ b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java @@ -4,6 +4,7 @@ import javafx.scene.input.DataFormat; +import org.jabref.logic.citationstyle.PreviewLayout; import org.jabref.model.entry.BibEntry; /** @@ -15,5 +16,6 @@ public class DragAndDropDataFormats { 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"); @SuppressWarnings("unchecked") public static final Class> BIBENTRY_LIST_CLASS = (Class>) (Class) List.class; - + public static final DataFormat PREVIEWLAYOUTS = new DataFormat("dnd/org.jabref.logic.citationstyle.PreviewLayouts"); + @SuppressWarnings("unchecked") public static final Class> PREVIEWLAYOUT_LIST_CLASS = (Class>) (Class) List.class; } diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index 326c1aa855a..d7d45501a8e 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import javafx.application.Platform; import javafx.event.Event; @@ -13,17 +14,18 @@ import javafx.scene.control.TitledPane; import javafx.scene.layout.FlowPane; +import org.jabref.Globals; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.ControlHelper; import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.importer.IdBasedFetcher; import org.jabref.logic.l10n.Localization; -import org.jabref.model.EntryTypes; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BiblatexEntryTypes; -import org.jabref.model.entry.BibtexEntryTypes; -import org.jabref.model.entry.EntryType; -import org.jabref.model.entry.IEEETranEntryTypes; +import org.jabref.model.entry.BibEntryType; +import org.jabref.model.entry.types.BiblatexEntryTypeDefinitions; +import org.jabref.model.entry.types.BibtexEntryTypeDefinitions; +import org.jabref.model.entry.types.EntryType; +import org.jabref.model.entry.types.IEEETranEntryTypeDefinitions; import org.jabref.preferences.JabRefPreferences; import com.airhacks.afterburner.views.ViewLoader; @@ -78,18 +80,17 @@ public EntryTypeView(BasePanel basePanel, DialogService dialogService, JabRefPre EasyBind.subscribe(viewModel.searchSuccesfulProperty(), value -> { if (value) { - setEntryTypeForReturnAndClose(null); + setEntryTypeForReturnAndClose(Optional.empty()); } }); } - private void addEntriesToPane(FlowPane pane, Collection entries) { - - for (EntryType entryType : entries) { - Button entryButton = new Button(entryType.getName()); + private void addEntriesToPane(FlowPane pane, Collection entries) { + for (BibEntryType entryType : entries) { + Button entryButton = new Button(entryType.getType().getDisplayName()); entryButton.setUserData(entryType); - entryButton.setOnAction(event -> setEntryTypeForReturnAndClose(entryType)); + entryButton.setOnAction(event -> setEntryTypeForReturnAndClose(Optional.of(entryType))); pane.getChildren().add(entryButton); } } @@ -119,12 +120,12 @@ public void initialize() { customTitlePane.managedProperty().bind(customTitlePane.visibleProperty()); if (basePanel.getBibDatabaseContext().isBiblatexMode()) { - addEntriesToPane(biblatexPane, BiblatexEntryTypes.ALL); + addEntriesToPane(biblatexPane, BiblatexEntryTypeDefinitions.ALL); bibTexTitlePane.setVisible(false); ieeeTranTitlePane.setVisible(false); - List customTypes = EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBLATEX); + List customTypes = Globals.entryTypesManager.getAllCustomTypes(BibDatabaseMode.BIBLATEX); if (customTypes.isEmpty()) { customTitlePane.setVisible(false); } else { @@ -133,10 +134,10 @@ public void initialize() { } else { biblatexTitlePane.setVisible(false); - addEntriesToPane(bibTexPane, BibtexEntryTypes.ALL); - addEntriesToPane(ieeetranPane, IEEETranEntryTypes.ALL); + addEntriesToPane(bibTexPane, BibtexEntryTypeDefinitions.ALL); + addEntriesToPane(ieeetranPane, IEEETranEntryTypeDefinitions.ALL); - List customTypes = EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBTEX); + List customTypes = Globals.entryTypesManager.getAllCustomTypes(BibDatabaseMode.BIBTEX); if (customTypes.isEmpty()) { customTitlePane.setVisible(false); } else { @@ -162,8 +163,8 @@ private void focusTextField(Event event) { idTextField.selectAll(); } - private void setEntryTypeForReturnAndClose(EntryType entryType) { - type = entryType; + private void setEntryTypeForReturnAndClose(Optional entryType) { + type = entryType.map(BibEntryType::getType).orElse(null); viewModel.stopFetching(); this.close(); } diff --git a/src/main/java/org/jabref/gui/EntryTypeViewModel.java b/src/main/java/org/jabref/gui/EntryTypeViewModel.java index f6956a4ac23..62344a16889 100644 --- a/src/main/java/org/jabref/gui/EntryTypeViewModel.java +++ b/src/main/java/org/jabref/gui/EntryTypeViewModel.java @@ -14,6 +14,7 @@ import javafx.concurrent.Task; import javafx.concurrent.Worker; +import org.jabref.Globals; import org.jabref.gui.duplicationFinder.DuplicateResolverDialog; import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; @@ -138,7 +139,7 @@ public void runFetcherWorker() { Optional result = fetcherWorker.getValue(); if (result.isPresent()) { final BibEntry entry = result.get(); - Optional duplicate = DuplicateCheck.containsDuplicate(basePanel.getDatabase(), entry, basePanel.getBibDatabaseContext().getMode()); + 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()); switch (dialog.showAndWait().orElse(DuplicateResolverDialog.DuplicateResolverResult.BREAK)) { diff --git a/src/main/java/org/jabref/gui/GUIGlobals.java b/src/main/java/org/jabref/gui/GUIGlobals.java index 12d55f69bbe..909465a1e43 100644 --- a/src/main/java/org/jabref/gui/GUIGlobals.java +++ b/src/main/java/org/jabref/gui/GUIGlobals.java @@ -1,11 +1,10 @@ package org.jabref.gui; -import java.awt.Color; -import java.awt.Font; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; import org.jabref.Globals; import org.jabref.gui.icon.IconTheme; -import org.jabref.gui.keyboard.EmacsKeyBindings; import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.logic.l10n.Localization; import org.jabref.preferences.JabRefPreferences; @@ -45,20 +44,15 @@ public static void updateEntryEditorColors() { * on Un*x is unavailable. */ public static void init() { - if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) { - EmacsKeyBindings.load(); - } - // Set up entry editor colors, first time: GUIGlobals.updateEntryEditorColors(); IconTheme.loadFonts(); - GUIGlobals.currentFont = new Font(Globals.prefs.get(JabRefPreferences.FONT_FAMILY), - Globals.prefs.getInt(JabRefPreferences.FONT_STYLE), Globals.prefs.getInt(JabRefPreferences.FONT_SIZE)); + GUIGlobals.currentFont = new Font(Globals.prefs.getFontFamily(), Globals.prefs.getDouble(JabRefPreferences.FONT_SIZE)); } - public static void setFont(int size) { - currentFont = new Font(currentFont.getFamily(), currentFont.getStyle(), size); + public static void setFont(double size) { + currentFont = new Font(currentFont.getFamily(), size); // update preferences Globals.prefs.putInt(JabRefPreferences.FONT_SIZE, size); } diff --git a/src/main/java/org/jabref/gui/JabRefDialog.java b/src/main/java/org/jabref/gui/JabRefDialog.java deleted file mode 100644 index 3221956a393..00000000000 --- a/src/main/java/org/jabref/gui/JabRefDialog.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.jabref.gui; - -import java.awt.Frame; - -import javax.swing.JDialog; - -import org.jabref.Globals; - -public class JabRefDialog extends JDialog { - - public JabRefDialog(boolean modal, Class clazz) { - this("JabRef", modal, clazz); - } - - public JabRefDialog(Class clazz) { - this(true, clazz); - } - - public JabRefDialog(String title, Class clazz) { - this(title, true, clazz); - } - - public JabRefDialog(String title, boolean modal, Class clazz) { - super((Frame) null, title, modal); - - trackDialogOpening(clazz); - } - - public JabRefDialog(java.awt.Dialog owner, String title, Class clazz) { - this(owner, title, true, clazz); - } - - public JabRefDialog(java.awt.Dialog owner, String title, boolean modal, Class clazz) { - super(owner, title, modal); - - trackDialogOpening(clazz); - } - - private void trackDialogOpening(Class clazz) { - Globals.getTelemetryClient().ifPresent(client -> client.trackPageView(clazz.getName())); - } - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - - if (visible) { - // FIXME: Ugly hack to ensure that new dialogs are not hidden behind the main window - setAlwaysOnTop(true); - requestFocus(); - setAlwaysOnTop(false); - } - } -} diff --git a/src/main/java/org/jabref/gui/JabRefDialogService.java b/src/main/java/org/jabref/gui/JabRefDialogService.java index 4ae2146a8b6..cde1170f3e8 100644 --- a/src/main/java/org/jabref/gui/JabRefDialogService.java +++ b/src/main/java/org/jabref/gui/JabRefDialogService.java @@ -165,6 +165,7 @@ public void showErrorDialogAndWait(String title, String content) { @Override public void showErrorDialogAndWait(String message, Throwable exception) { ExceptionDialog exceptionDialog = new ExceptionDialog(exception); + exceptionDialog.getDialogPane().setMaxWidth(mainWindow.getWidth() / 2); exceptionDialog.setHeaderText(message); exceptionDialog.showAndWait(); } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index e70d9429b6d..d1b82f480c0 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -14,9 +14,6 @@ import java.util.TimerTask; import java.util.stream.Collectors; -import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; - import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -28,6 +25,7 @@ import javafx.scene.control.ButtonType; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; import javafx.scene.control.ProgressBar; import javafx.scene.control.Separator; import javafx.scene.control.SeparatorMenuItem; @@ -100,6 +98,7 @@ import org.jabref.gui.search.GlobalSearchBar; import org.jabref.gui.shared.ConnectToSharedDatabaseCommand; import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; +import org.jabref.gui.texparser.ParseTexAction; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; @@ -119,9 +118,9 @@ import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.database.shared.DatabaseLocation; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BiblatexEntryTypes; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.specialfields.SpecialField; +import org.jabref.model.entry.field.SpecialField; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.LastFocusedTabPreferences; @@ -154,7 +153,7 @@ public class JabRefFrame extends BorderPane { private final CountingUndoManager undoManager; private SidePaneManager sidePaneManager; private TabPane tabbedPane; - private PushToApplicationsManager pushApplications; + private final PushToApplicationsManager pushToApplicationsManager; private final DialogService dialogService; private SidePane sidePane; @@ -162,6 +161,7 @@ public JabRefFrame(Stage mainStage) { this.mainStage = mainStage; this.dialogService = new JabRefDialogService(mainStage, this); this.stateManager = Globals.stateManager; + this.pushToApplicationsManager = new PushToApplicationsManager(dialogService, stateManager); this.undoManager = Globals.undoManager; } @@ -291,9 +291,7 @@ private void initShowTrackingNotification() { @Override public void run() { - SwingUtilities.invokeLater(() -> { DefaultTaskExecutor.runInJavaFXThread(JabRefFrame.this::showTrackingNotification); - }); } }, 60000); // run in one minute } @@ -399,6 +397,8 @@ private void tearDownJabRef(List filenames) { prefs.flush(); // dispose all windows, even if they are not displayed anymore + // TODO: javafx variant only avaiable in java 9 and updwards + // https://docs.oracle.com/javase/9/docs/api/javafx/stage/Window.html#getWindows-- for (Window window : Window.getWindows()) { window.dispose(); } @@ -449,8 +449,6 @@ public boolean quit() { private void initLayout() { setProgressBarVisible(false); - pushApplications = new PushToApplicationsManager(this.getDialogService()); - BorderPane head = new BorderPane(); head.setTop(createMenu()); head.setCenter(createToolbar()); @@ -520,9 +518,13 @@ private Node createToolbar() { leftSide.prefWidthProperty().bind(sidePane.widthProperty()); leftSide.maxWidthProperty().bind(sidePane.widthProperty()); - PushToApplicationAction pushToApplicationAction = new PushToApplicationAction(stateManager, this.getPushApplications(), this.getDialogService()); + final PushToApplicationAction pushToApplicationAction = getPushToApplicationsManager().getPushToApplicationAction(); + final Button pushToApplicationButton = factory.createIconButton(pushToApplicationAction.getActionInformation(), pushToApplicationAction); + pushToApplicationsManager.setToolBarButton(pushToApplicationButton); + HBox rightSide = new HBox( - factory.createIconButton(StandardActions.NEW_ARTICLE, new NewEntryAction(this, BiblatexEntryTypes.ARTICLE, dialogService, Globals.prefs, stateManager)), + factory.createIconButton(StandardActions.NEW_ARTICLE, new NewEntryAction(this, StandardEntryType.Article, dialogService, Globals.prefs, stateManager)), + factory.createIconButton(StandardActions.NEW_ENTRY, new NewEntryAction(this, dialogService, Globals.prefs, stateManager)), factory.createIconButton(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, stateManager)), new Separator(Orientation.VERTICAL), factory.createIconButton(StandardActions.UNDO, new OldDatabaseCommandWrapper(Actions.UNDO, this, stateManager)), @@ -531,7 +533,7 @@ private Node createToolbar() { factory.createIconButton(StandardActions.COPY, new OldDatabaseCommandWrapper(Actions.COPY, this, stateManager)), factory.createIconButton(StandardActions.PASTE, new OldDatabaseCommandWrapper(Actions.PASTE, this, stateManager)), new Separator(Orientation.VERTICAL), - factory.createIconButton(pushToApplicationAction.getActionInformation(), pushToApplicationAction), + pushToApplicationButton, factory.createIconButton(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, stateManager)), factory.createIconButton(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, stateManager)), new Separator(Orientation.VERTICAL), @@ -756,11 +758,16 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction(this, prefs, stateManager, undoManager)) + factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction(this, prefs, stateManager, undoManager, Globals.TASK_EXECUTOR)) ); - final PushToApplicationAction pushToApplicationAction = new PushToApplicationAction(stateManager, this.getPushApplications(), this.getDialogService()); + // PushToApplication + final PushToApplicationAction pushToApplicationAction = pushToApplicationsManager.getPushToApplicationAction(); + final MenuItem pushToApplicationMenuItem = factory.createMenuItem(pushToApplicationAction.getActionInformation(), pushToApplicationAction); + pushToApplicationsManager.setMenuItem(pushToApplicationMenuItem); + tools.getItems().addAll( + factory.createMenuItem(StandardActions.PARSE_TEX, new ParseTexAction(stateManager)), factory.createMenuItem(StandardActions.NEW_SUB_LIBRARY_FROM_AUX, new NewSubLibraryAction(this, stateManager)), factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this, stateManager)), factory.createMenuItem(StandardActions.WRITE_XMP, new OldDatabaseCommandWrapper(Actions.WRITE_XMP, this, stateManager)), @@ -776,7 +783,7 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, stateManager)), factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, stateManager)), factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, stateManager)), - factory.createMenuItem(pushToApplicationAction.getActionInformation(), pushToApplicationAction), + pushToApplicationMenuItem, factory.createSubMenu(StandardActions.ABBREVIATE, factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, stateManager)), @@ -799,7 +806,6 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createCheckMenuItem(StandardActions.TOGGLE_PREVIEW, new OldDatabaseCommandWrapper(Actions.TOGGLE_PREVIEW, this, stateManager), Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()), factory.createMenuItem(StandardActions.NEXT_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.NEXT_PREVIEW_STYLE, this, stateManager)), factory.createMenuItem(StandardActions.PREVIOUS_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.PREVIOUS_PREVIEW_STYLE, this, stateManager)), @@ -997,7 +1003,7 @@ public void addTab(BasePanel basePanel, boolean raisePanel) { autosaver.registerListener(new AutosaveUIManager(basePanel)); } - BackupManager.start(context); + BackupManager.start(context, Globals.entryTypesManager, prefs); // Track opening trackOpenNewDatabase(basePanel); @@ -1054,18 +1060,9 @@ public void setProgressBarVisible(final boolean visible) { /** * Sets the indeterminate status of the progress bar. *

- * If not called on the event dispatch thread, this method uses SwingUtilities.invokeLater() to do the actual - * operation on the EDT. */ public void setProgressBarIndeterminate(final boolean value) { - // TODO: Reimplement - /* - if (SwingUtilities.isEventDispatchThread()) { - progressBar.setIndeterminate(value); - } else { - SwingUtilities.invokeLater(() -> progressBar.setIndeterminate(value)); - } - */ + progressBar.setProgress(ProgressBar.INDETERMINATE_PROGRESS); } /** @@ -1078,7 +1075,7 @@ public void setProgressBarIndeterminate(final boolean value) { private boolean isExistFile(List selectEntryList) { if (selectEntryList.size() == 1) { BibEntry selectedEntry = selectEntryList.get(0); - return selectedEntry.getField(FieldName.FILE).isPresent(); + return selectedEntry.getField(StandardField.FILE).isPresent(); } return false; } @@ -1093,15 +1090,11 @@ private boolean isExistFile(List selectEntryList) { private boolean isExistURLorDOI(List selectEntryList) { if (selectEntryList.size() == 1) { BibEntry selectedEntry = selectEntryList.get(0); - return (selectedEntry.getField(FieldName.URL).isPresent() || selectedEntry.getField(FieldName.DOI).isPresent()); + return (selectedEntry.getField(StandardField.URL).isPresent() || selectedEntry.getField(StandardField.DOI).isPresent()); } return false; } - public void showMessage(String message) { - JOptionPane.showMessageDialog(null, message); - } - /** * Ask if the user really wants to close the given database * @@ -1192,8 +1185,8 @@ public SidePaneManager getSidePaneManager() { return sidePaneManager; } - public PushToApplicationsManager getPushApplications() { - return pushApplications; + public PushToApplicationsManager getPushToApplicationsManager() { + return pushToApplicationsManager; } public GlobalSearchBar getGlobalSearchBar() { @@ -1246,7 +1239,7 @@ public void execute() { textInput.cut(); break; case PASTE: - textInput.paste(); + // handled by FX in TextInputControl#paste break; default: throw new IllegalStateException("Only cut/copy/paste supported but got " + command); @@ -1261,7 +1254,7 @@ public void execute() { getCurrentBasePanel().cut(); break; case PASTE: - getCurrentBasePanel().paste(); + // handled by FX in TextInputControl#paste break; default: throw new IllegalStateException("Only cut/copy/paste supported but got " + command); @@ -1288,7 +1281,7 @@ private void increaseTableFontSize() { } private void decreaseTableFontSize() { - int currentSize = GUIGlobals.currentFont.getSize(); + double currentSize = GUIGlobals.currentFont.getSize(); if (currentSize < 2) { return; } diff --git a/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java index aeca6f4ddad..2c4ef4c5f6f 100644 --- a/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java +++ b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java @@ -10,6 +10,7 @@ import javafx.scene.layout.GridPane; import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.field.Field; import org.jabref.model.metadata.SaveOrderConfig; import org.jabref.preferences.PreferencesService; @@ -20,9 +21,9 @@ public class SaveOrderConfigDisplayView extends GridPane { private final SaveOrderConfig config; @FXML private ToggleGroup saveOrderToggleGroup; - @FXML private ComboBox savePriSort; - @FXML private ComboBox saveSecSort; - @FXML private ComboBox saveTerSort; + @FXML private ComboBox savePriSort; + @FXML private ComboBox saveSecSort; + @FXML private ComboBox saveTerSort; @FXML private RadioButton exportInSpecifiedOrder; @FXML private RadioButton exportInTableOrder; @FXML private RadioButton exportInOriginalOrder; diff --git a/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java index 0846ee4866c..cc06c9e8cd9 100644 --- a/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java +++ b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java @@ -1,37 +1,35 @@ package org.jabref.gui; -import java.util.Collections; -import java.util.List; -import java.util.Locale; import java.util.Objects; +import java.util.Set; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ListProperty; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleListProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; +import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.InternalBibtexFields; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.metadata.SaveOrderConfig; import org.jabref.model.metadata.SaveOrderConfig.SortCriterion; import org.jabref.preferences.PreferencesService; public class SaveOrderConfigDisplayViewModel { - private final ListProperty priSortFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); - private final ListProperty secSortFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); - private final ListProperty terSortFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final ListProperty priSortFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final ListProperty secSortFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final ListProperty terSortFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); private final BooleanProperty savePriDescPropertySelected = new SimpleBooleanProperty(); private final BooleanProperty saveSecDescPropertySelected = new SimpleBooleanProperty(); private final BooleanProperty saveTerDescPropertySelected = new SimpleBooleanProperty(); - private final StringProperty savePriSortSelectedValueProperty = new SimpleStringProperty(""); - private final StringProperty saveSecSortSelectedValueProperty = new SimpleStringProperty(""); - private final StringProperty saveTerSortSelectedValueProperty = new SimpleStringProperty(""); + private final ObjectProperty savePriSortSelectedValueProperty = new SimpleObjectProperty<>(null); + private final ObjectProperty saveSecSortSelectedValueProperty = new SimpleObjectProperty<>(null); + private final ObjectProperty saveTerSortSelectedValueProperty = new SimpleObjectProperty<>(null); private final BooleanProperty saveInOriginalProperty = new SimpleBooleanProperty(); private final BooleanProperty saveInTableOrderProperty = new SimpleBooleanProperty(); @@ -42,10 +40,7 @@ public class SaveOrderConfigDisplayViewModel { public SaveOrderConfigDisplayViewModel(SaveOrderConfig config, PreferencesService prefs) { this.prefs = prefs; - List fieldNames = InternalBibtexFields.getAllPublicFieldNames(); - fieldNames.add(BibEntry.KEY_FIELD); - Collections.sort(fieldNames); - + Set fieldNames = FieldFactory.getCommonFields(); priSortFieldsProperty.addAll(fieldNames); secSortFieldsProperty.addAll(fieldNames); terSortFieldsProperty.addAll(fieldNames); @@ -53,26 +48,24 @@ public SaveOrderConfigDisplayViewModel(SaveOrderConfig config, PreferencesServic setSaveOrderConfig(config); } - public ListProperty priSortFieldsProperty() { + public ListProperty priSortFieldsProperty() { return priSortFieldsProperty; } - public ListProperty secSortFieldsProperty() { + public ListProperty secSortFieldsProperty() { return secSortFieldsProperty; } - public ListProperty terSortFieldsProperty() { + public ListProperty terSortFieldsProperty() { return terSortFieldsProperty; } public SaveOrderConfig getSaveOrderConfig() { - SortCriterion primary = new SortCriterion(getSelectedItemAsLowerCaseTrim(savePriSortSelectedValueProperty), savePriDescPropertySelected.getValue()); - SortCriterion secondary = new SortCriterion(getSelectedItemAsLowerCaseTrim(saveSecSortSelectedValueProperty), saveSecDescPropertySelected.getValue()); - SortCriterion tertiary = new SortCriterion(getSelectedItemAsLowerCaseTrim(saveTerSortSelectedValueProperty), saveTerDescPropertySelected.getValue()); - - SaveOrderConfig saveOrderConfig = new SaveOrderConfig(saveInOriginalProperty.getValue(), saveInSpecifiedOrderProperty.getValue(), primary, secondary, tertiary); + SortCriterion primary = new SortCriterion(savePriSortSelectedValueProperty.get(), savePriDescPropertySelected.getValue()); + SortCriterion secondary = new SortCriterion(saveSecSortSelectedValueProperty.get(), saveSecDescPropertySelected.getValue()); + SortCriterion tertiary = new SortCriterion(saveTerSortSelectedValueProperty.get(), saveTerDescPropertySelected.getValue()); - return saveOrderConfig; + return new SaveOrderConfig(saveInOriginalProperty.getValue(), saveInSpecifiedOrderProperty.getValue(), primary, secondary, tertiary); } public void setSaveOrderConfig(SaveOrderConfig saveOrderConfig) { @@ -95,10 +88,6 @@ public void setSaveOrderConfig(SaveOrderConfig saveOrderConfig) { } - private String getSelectedItemAsLowerCaseTrim(StringProperty string) { - return string.getValue().toLowerCase(Locale.ROOT).trim(); - } - public BooleanProperty savePriDescPropertySelected() { return savePriDescPropertySelected; } @@ -111,15 +100,15 @@ public BooleanProperty saveTerDescPropertySelected() { return saveTerDescPropertySelected; } - public StringProperty savePriSortSelectedValueProperty() { + public ObjectProperty savePriSortSelectedValueProperty() { return savePriSortSelectedValueProperty; } - public StringProperty saveSecSortSelectedValueProperty() { + public ObjectProperty saveSecSortSelectedValueProperty() { return saveSecSortSelectedValueProperty; } - public StringProperty saveTerSortSelectedValueProperty() { + public ObjectProperty saveTerSortSelectedValueProperty() { return saveTerSortSelectedValueProperty; } diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index 630d5511eb9..f9a0076d70f 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -6,6 +6,7 @@ import java.util.stream.Collectors; import javafx.beans.binding.Bindings; +import javafx.beans.property.IntegerProperty; import javafx.beans.property.ReadOnlyListProperty; import javafx.beans.property.ReadOnlyListWrapper; import javafx.collections.FXCollections; @@ -23,9 +24,8 @@ * This class manages the GUI-state of JabRef, including: * - currently selected database * - currently selected group - * Coming soon: - * - open databases * - active search + * - active number of search results */ public class StateManager { @@ -34,6 +34,7 @@ public class StateManager { private final ObservableList selectedEntries = FXCollections.observableArrayList(); private final ObservableMap> selectedGroups = FXCollections.observableHashMap(); private final OptionalObjectProperty activeSearchQuery = OptionalObjectProperty.empty(); + private final ObservableMap searchResultMap = FXCollections.observableHashMap(); public StateManager() { activeGroups.bind(Bindings.valueAt(selectedGroups, activeDatabase.orElse(null))); @@ -47,6 +48,14 @@ public OptionalObjectProperty activeSearchQueryProperty() { return activeSearchQuery; } + public void setActiveSearchResultSize(BibDatabaseContext database, IntegerProperty resultSize) { + searchResultMap.put(database, resultSize); + } + + public IntegerProperty getSearchResultSize() { + return searchResultMap.get(activeDatabase.getValue().orElse(new BibDatabaseContext())); + } + public ReadOnlyListProperty activeGroupProperty() { return activeGroups.getReadOnlyProperty(); } @@ -79,7 +88,7 @@ public Optional getActiveDatabase() { public List getEntriesInCurrentDatabase() { return OptionalUtil.flatMap(activeDatabase.get(), BibDatabaseContext::getEntries) - .collect(Collectors.toList()); + .collect(Collectors.toList()); } public void clearSearchQuery() { diff --git a/src/main/java/org/jabref/gui/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java index 07a8ddb3f2f..60625d13a1a 100644 --- a/src/main/java/org/jabref/gui/actions/ActionFactory.java +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -4,7 +4,6 @@ import java.lang.reflect.Method; import java.util.Objects; -import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ButtonBase; import javafx.scene.control.CheckMenuItem; @@ -148,13 +147,9 @@ public ButtonBase configureIconButton(Action action, Command command, ButtonBase button.getStyleClass().add("icon-button"); // For some reason the graphic is not set correctly, so let's fix this + // ToDO: Find a way to reuse JabRefIconView button.graphicProperty().unbind(); - action.getIcon().ifPresent(icon -> { - // ToDO: Find a way to reuse JabRefIconView - Node graphicNode = icon.getGraphicNode(); - graphicNode.setStyle(String.format("-fx-font-family: %s; -fx-font-size: %s;", icon.fontFamily(), "1em")); - button.setGraphic(graphicNode); - }); + action.getIcon().ifPresent(icon -> button.setGraphic(icon.getGraphicNode())); return button; } diff --git a/src/main/java/org/jabref/gui/actions/Actions.java b/src/main/java/org/jabref/gui/actions/Actions.java index 5348e3394ae..b113f289632 100644 --- a/src/main/java/org/jabref/gui/actions/Actions.java +++ b/src/main/java/org/jabref/gui/actions/Actions.java @@ -49,7 +49,6 @@ public enum Actions { SELECT_ALL, SEND_AS_EMAIL, TOGGLE_GROUPS, - TOGGLE_PREVIEW, UNABBREVIATE, UNDO, WRITE_XMP, diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index eb4c6508955..6485c626d0e 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -85,6 +85,7 @@ public enum StandardActions implements Action { TOOGLE_OO(Localization.lang("OpenOffice/LibreOffice"), IconTheme.JabRefIcons.FILE_OPENOFFICE, KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION), TOGGLE_WEB_SEARCH(Localization.lang("Web search"), Localization.lang("Toggle web search interface"), IconTheme.JabRefIcons.WWW, KeyBinding.WEB_SEARCH), + PARSE_TEX(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_FOLDER(Localization.lang("Open folder"), Localization.lang("Open folder"), KeyBinding.OPEN_FOLDER), @@ -112,13 +113,12 @@ public enum StandardActions implements Action { 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), - TOGGLE_PREVIEW(Localization.lang("Entry preview"), IconTheme.JabRefIcons.TOGGLE_ENTRY_PREVIEW, KeyBinding.TOGGLE_ENTRY_PREVIEW), NEXT_PREVIEW_STYLE(Localization.lang("Next citation style"), KeyBinding.NEXT_PREVIEW_LAYOUT), PREVIOUS_PREVIEW_STYLE(Localization.lang("Previous citation style"), KeyBinding.PREVIOUS_PREVIEW_LAYOUT), SELECT_ALL(Localization.lang("Select all"), KeyBinding.SELECT_ALL), NEW_ENTRY(Localization.lang("New entry"), IconTheme.JabRefIcons.ADD_ENTRY, KeyBinding.NEW_ENTRY), - NEW_ARTICLE(Localization.lang("New article"), IconTheme.JabRefIcons.ADD_ENTRY), + NEW_ARTICLE(Localization.lang("New article"), IconTheme.JabRefIcons.ADD_ARTICLE), NEW_ENTRY_FROM_PLAINTEX(Localization.lang("New entry from plain text"), KeyBinding.NEW_FROM_PLAIN_TEXT), LIBRARY_PROPERTIES(Localization.lang("Library properties")), EDIT_PREAMBLE(Localization.lang("Edit preamble")), diff --git a/src/main/java/org/jabref/gui/autocompleter/AutoCompletePreferences.java b/src/main/java/org/jabref/gui/autocompleter/AutoCompletePreferences.java index 1a54be767f1..bd2088e6a3c 100644 --- a/src/main/java/org/jabref/gui/autocompleter/AutoCompletePreferences.java +++ b/src/main/java/org/jabref/gui/autocompleter/AutoCompletePreferences.java @@ -1,22 +1,21 @@ package org.jabref.gui.autocompleter; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; +import java.util.Set; import org.jabref.logic.journals.JournalAbbreviationPreferences; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; public class AutoCompletePreferences { - private static final String DELIMITER = ";"; private boolean shouldAutoComplete; private AutoCompleteFirstNameMode firstNameMode; private boolean onlyCompleteLastFirst; private boolean onlyCompleteFirstLast; - private List completeFields; + private Set completeFields; private final JournalAbbreviationPreferences journalAbbreviationPreferences; - public AutoCompletePreferences(boolean shouldAutoComplete, AutoCompleteFirstNameMode firstNameMode, boolean onlyCompleteLastFirst, boolean onlyCompleteFirstLast, List completeFields, JournalAbbreviationPreferences journalAbbreviationPreferences) { + public AutoCompletePreferences(boolean shouldAutoComplete, AutoCompleteFirstNameMode firstNameMode, boolean onlyCompleteLastFirst, boolean onlyCompleteFirstLast, Set completeFields, JournalAbbreviationPreferences journalAbbreviationPreferences) { this.shouldAutoComplete = shouldAutoComplete; this.firstNameMode = firstNameMode; this.onlyCompleteLastFirst = onlyCompleteLastFirst; @@ -64,20 +63,20 @@ public void setOnlyCompleteFirstLast(boolean onlyCompleteFirstLast) { * Returns the list of fields for which autocomplete is enabled * @return List of field names */ - public List getCompleteFields() { + public Set getCompleteFields() { return completeFields; } - public void setCompleteFields(List completeFields) { + public void setCompleteFields(Set completeFields) { this.completeFields = completeFields; } public void setCompleteNames(String input) { - setCompleteFields(Arrays.asList(input.split(DELIMITER))); + setCompleteFields(FieldFactory.parseFieldList(input)); } public String getCompleteNamesAsString() { - return completeFields.stream().collect(Collectors.joining(DELIMITER)); + return FieldFactory.serializeFieldsList(completeFields); } public JournalAbbreviationPreferences getJournalAbbreviationPreferences() { diff --git a/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java index db1e4546b6b..3a5ecbffae4 100644 --- a/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java @@ -4,6 +4,7 @@ import org.jabref.logic.bibtex.comparator.EntryComparator; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.InternalField; import org.controlsfx.control.textfield.AutoCompletionBinding; @@ -23,7 +24,7 @@ public void indexEntry(BibEntry entry) { @Override protected Comparator getComparator() { - return new EntryComparator(false, true, BibEntry.KEY_FIELD); + return new EntryComparator(false, true, InternalField.KEY_FIELD); } @Override diff --git a/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java index 871723b2cd7..87048951ec4 100644 --- a/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java @@ -3,16 +3,17 @@ import java.util.Objects; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; /** * Stores the full content of one field. */ class FieldValueSuggestionProvider extends StringSuggestionProvider implements AutoCompleteSuggestionProvider { - private final String fieldName; + private final Field field; - FieldValueSuggestionProvider(String fieldName) { - this.fieldName = Objects.requireNonNull(fieldName); + FieldValueSuggestionProvider(Field field) { + this.field = Objects.requireNonNull(field); } @Override @@ -21,6 +22,6 @@ public void indexEntry(BibEntry entry) { return; } - entry.getField(fieldName).ifPresent(fieldValue -> addPossibleSuggestions(fieldValue.trim())); + entry.getField(field).ifPresent(fieldValue -> addPossibleSuggestions(fieldValue.trim())); } } diff --git a/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java index f0749e3c7c7..5e8b5c95f4d 100644 --- a/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java @@ -6,13 +6,13 @@ import org.jabref.logic.journals.Abbreviation; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationPreferences; +import org.jabref.model.entry.field.Field; public class JournalsSuggestionProvider extends FieldValueSuggestionProvider { - - JournalsSuggestionProvider(String fieldName, AutoCompletePreferences preferences, + JournalsSuggestionProvider(Field field, AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { - super(fieldName); + super(field); JournalAbbreviationPreferences journalAbbreviationPreferences = preferences.getJournalAbbreviationPreferences(); List journals = abbreviationLoader.getRepository(journalAbbreviationPreferences) diff --git a/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java index 8182be6a33c..db84646648d 100644 --- a/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java @@ -1,13 +1,14 @@ package org.jabref.gui.autocompleter; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.List; import java.util.Objects; import org.jabref.model.entry.Author; import org.jabref.model.entry.AuthorList; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; import org.controlsfx.control.textfield.AutoCompletionBinding; @@ -16,17 +17,17 @@ */ public class PersonNameSuggestionProvider extends SuggestionProvider implements AutoCompleteSuggestionProvider { - private final List fieldNames; + private final Collection fields; private final Comparator authorComparator = Comparator.comparing(Author::getNameForAlphabetization); - PersonNameSuggestionProvider(String fieldName) { + PersonNameSuggestionProvider(Field fieldName) { this(Collections.singletonList(Objects.requireNonNull(fieldName))); } - public PersonNameSuggestionProvider(List fieldNames) { + public PersonNameSuggestionProvider(Collection fields) { super(); - this.fieldNames = Objects.requireNonNull(fieldNames); + this.fields = Objects.requireNonNull(fields); } @@ -36,8 +37,8 @@ public void indexEntry(BibEntry entry) { return; } - for (String fieldName : fieldNames) { - entry.getField(fieldName).ifPresent(fieldValue -> { + for (Field field : fields) { + entry.getField(field).ifPresent(fieldValue -> { AuthorList authorList = AuthorList.parse(fieldValue); for (Author author : authorList.getAuthors()) { addPossibleSuggestions(author); diff --git a/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java b/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java index a4bf835a19b..4f8f76a405c 100644 --- a/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java +++ b/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java @@ -1,23 +1,23 @@ package org.jabref.gui.autocompleter; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.FieldProperty; -import org.jabref.model.entry.InternalBibtexFields; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldProperty; +import org.jabref.model.entry.field.StandardField; public class SuggestionProviders { /** * key: field name */ - private final Map> providers = new HashMap<>(); + private final Map> providers = new HashMap<>(); /** * Empty @@ -30,15 +30,15 @@ public SuggestionProviders(AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { Objects.requireNonNull(preferences); - List completeFields = preferences.getCompleteFields(); - for (String field : completeFields) { + Set completeFields = preferences.getCompleteFields(); + for (Field field : completeFields) { AutoCompleteSuggestionProvider autoCompleter = initalizeSuggestionProvider(field, preferences, abbreviationLoader); providers.put(field, autoCompleter); } } - public AutoCompleteSuggestionProvider getForField(String fieldName) { - return providers.get(fieldName); + public AutoCompleteSuggestionProvider getForField(Field field) { + return providers.get(field); } public void indexDatabase(BibDatabase database) { @@ -56,16 +56,17 @@ public void indexEntry(BibEntry bibEntry) { } } - private AutoCompleteSuggestionProvider initalizeSuggestionProvider(String fieldName, AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { - if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.PERSON_NAMES)) { - return new PersonNameSuggestionProvider(fieldName); - } else if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.SINGLE_ENTRY_LINK)) { + private AutoCompleteSuggestionProvider initalizeSuggestionProvider(Field field, AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { + Set fieldProperties = field.getProperties(); + if (fieldProperties.contains(FieldProperty.PERSON_NAMES)) { + return new PersonNameSuggestionProvider(field); + } else if (fieldProperties.contains(FieldProperty.SINGLE_ENTRY_LINK)) { return new BibEntrySuggestionProvider(); - } else if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.JOURNAL_NAME) - || FieldName.PUBLISHER.equals(fieldName)) { - return new JournalsSuggestionProvider(fieldName, preferences, abbreviationLoader); + } else if (fieldProperties.contains(FieldProperty.JOURNAL_NAME) + || StandardField.PUBLISHER.equals(field)) { + return new JournalsSuggestionProvider(field, preferences, abbreviationLoader); } else { - return new WordSuggestionProvider(fieldName); + return new WordSuggestionProvider(field); } } } diff --git a/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java index 0f9c2ec56fa..a591d684a3b 100644 --- a/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java @@ -4,6 +4,7 @@ import java.util.StringTokenizer; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; /** * Stores all words in the given field which are separated by SEPARATING_CHARS. @@ -12,10 +13,10 @@ public class WordSuggestionProvider extends StringSuggestionProvider implements private static final String SEPARATING_CHARS = ";,\n "; - private final String fieldName; + private final Field field; - public WordSuggestionProvider(String fieldName) { - this.fieldName = Objects.requireNonNull(fieldName); + public WordSuggestionProvider(Field field) { + this.field = Objects.requireNonNull(field); } @Override @@ -24,7 +25,7 @@ public void indexEntry(BibEntry entry) { return; } - entry.getField(fieldName).ifPresent(fieldValue -> { + entry.getField(field).ifPresent(fieldValue -> { StringTokenizer tok = new StringTokenizer(fieldValue, SEPARATING_CHARS); while (tok.hasMoreTokens()) { addPossibleSuggestions(tok.nextToken()); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index e1e81d2bc03..34c1fd863b6 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -1,7 +1,6 @@ package org.jabref.gui.bibtexkeypattern; import java.util.HashMap; -import java.util.Locale; import java.util.Map; import javafx.scene.Node; @@ -18,12 +17,12 @@ import org.jabref.gui.help.HelpAction; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; -import org.jabref.model.EntryTypes; import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; import org.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern; import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.EntryType; +import org.jabref.model.entry.BibEntryType; +import org.jabref.model.entry.types.EntryType; import org.jabref.preferences.JabRefPreferences; public class BibtexKeyPatternPanel extends Pane { @@ -32,7 +31,7 @@ public class BibtexKeyPatternPanel extends Pane { protected final TextField defaultPat = new TextField(); // one field for each type - private final Map textFields = new HashMap<>(); + private final Map textFields = new HashMap<>(); private final BasePanel panel; private final GridPane gridPane = new GridPane(); @@ -43,6 +42,14 @@ public BibtexKeyPatternPanel(BasePanel panel) { buildGUI(); } + private static void setValue(TextField tf, EntryType fieldName, AbstractBibtexKeyPattern keyPattern) { + if (keyPattern.isDefaultValue(fieldName)) { + tf.setText(""); + } else { + tf.setText(keyPattern.getValue(fieldName).get(0)); + } + } + private void buildGUI() { BibDatabaseMode mode; // check mode of currently used DB @@ -74,8 +81,8 @@ private void buildGUI() { gridPane.add(button, 3, rowIndex); columnIndex = 1; - for (EntryType type : EntryTypes.getAllValues(mode)) { - Label label1 = new Label(type.getName()); + for (BibEntryType type : Globals.entryTypesManager.getAllTypes(mode)) { + 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))); @@ -84,7 +91,7 @@ private void buildGUI() { gridPane.add(textField, 2 + (columnIndex * 3), rowIndex); gridPane.add(button1, 3 + (columnIndex * 3), rowIndex); - textFields.put(type.getName().toLowerCase(Locale.ROOT), textField); + textFields.put(type.getType(), textField); if (columnIndex == (columnsNumber - 1)) { columnIndex = 0; @@ -111,12 +118,24 @@ private void buildGUI() { gridPane.add(btnDefaultAll1, 2, rowIndex); } + protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() { + GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern(Globals.prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + fillPatternUsingPanelData(res); + return res; + } + + public DatabaseBibtexKeyPattern getKeyPatternAsDatabaseBibtexKeyPattern() { + DatabaseBibtexKeyPattern res = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern()); + fillPatternUsingPanelData(res); + return res; + } + /** * fill the given LabelPattern by values generated from the text fields */ private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { // each entry type - for (Map.Entry entry : textFields.entrySet()) { + for (Map.Entry entry : textFields.entrySet()) { String text = entry.getValue().getText(); if (!text.trim().isEmpty()) { keypatterns.addBibtexKeyPattern(entry.getKey(), text); @@ -130,25 +149,13 @@ private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { } } - protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() { - GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern(Globals.prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); - fillPatternUsingPanelData(res); - return res; - } - - public DatabaseBibtexKeyPattern getKeyPatternAsDatabaseBibtexKeyPattern() { - DatabaseBibtexKeyPattern res = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern()); - fillPatternUsingPanelData(res); - return res; - } - /** * Fills the current values to the text fields * * @param keyPattern the BibtexKeyPattern to use as initial value */ public void setValues(AbstractBibtexKeyPattern keyPattern) { - for (Map.Entry entry : textFields.entrySet()) { + for (Map.Entry entry : textFields.entrySet()) { setValue(entry.getValue(), entry.getKey(), keyPattern); } @@ -159,14 +166,6 @@ public void setValues(AbstractBibtexKeyPattern keyPattern) { } } - private static void setValue(TextField tf, String fieldName, AbstractBibtexKeyPattern keyPattern) { - if (keyPattern.isDefaultValue(fieldName)) { - tf.setText(""); - } else { - tf.setText(keyPattern.getValue(fieldName).get(0)); - } - } - public Node getPanel() { return gridPane; } diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupPresetPanel.java b/src/main/java/org/jabref/gui/cleanup/CleanupPresetPanel.java index 9149ef4a5f0..719c11bc267 100644 --- a/src/main/java/org/jabref/gui/cleanup/CleanupPresetPanel.java +++ b/src/main/java/org/jabref/gui/cleanup/CleanupPresetPanel.java @@ -15,7 +15,7 @@ import org.jabref.logic.cleanup.Cleanups; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.field.StandardField; import org.jabref.model.metadata.FilePreferences; import com.airhacks.afterburner.views.ViewLoader; @@ -62,7 +62,7 @@ private void init(CleanupPreset cleanupPreset, FilePreferences filePreferences) cleanUpRenamePDFonlyRelativePaths.disableProperty().bind(cleanUpRenamePDF.selectedProperty().not()); - cleanUpUpgradeExternalLinks.setText(Localization.lang("Upgrade external PDF/PS links to use the '%0' field.", FieldName.FILE)); + cleanUpUpgradeExternalLinks.setText(Localization.lang("Upgrade external PDF/PS links to use the '%0' field.", StandardField.FILE.getDisplayName())); cleanUpFormatters = new FieldFormatterCleanupsPanel(Localization.lang("Run field formatter:"), Cleanups.DEFAULT_SAVE_ACTIONS); formatterContainer.getChildren().setAll(cleanUpFormatters); diff --git a/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java b/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java index ab544366e0d..12cd47ccf92 100644 --- a/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java +++ b/src/main/java/org/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java @@ -1,9 +1,9 @@ package org.jabref.gui.cleanup; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -29,8 +29,9 @@ import org.jabref.model.cleanup.FieldFormatterCleanups; import org.jabref.model.cleanup.Formatter; import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.InternalBibtexFields; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; +import org.jabref.model.entry.field.InternalField; import org.jabref.model.metadata.MetaData; import org.fxmisc.easybind.EasyBind; @@ -42,7 +43,7 @@ public class FieldFormatterCleanupsPanel extends GridPane { private FieldFormatterCleanups fieldFormatterCleanups; private ListView actionsList; private ComboBox formattersCombobox; - private ComboBox selectFieldCombobox; + private ComboBox selectFieldCombobox; private Button addButton; private Label descriptionAreaText; private Button removeButton; @@ -104,7 +105,7 @@ private void buildLayout() { actionsList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); new ViewModelListCellFactory() .withText(action -> action.getField() + ": " + action.getFormatter().getName()) - .withTooltip(action -> action.getFormatter().getDescription()) + .withStringTooltip(action -> action.getFormatter().getDescription()) .install(actionsList); add(actionsList, 1, 1, 3, 1); @@ -161,17 +162,16 @@ private void updateDescription() { */ private GridPane getSelectorPanel() { GridPane builder = new GridPane(); - List fieldNames = InternalBibtexFields.getAllPublicAndInternalFieldNames(); - fieldNames.add(BibEntry.KEY_FIELD); - Collections.sort(fieldNames); - selectFieldCombobox = new ComboBox<>(FXCollections.observableArrayList(fieldNames)); + Set fields = FieldFactory.getCommonFields(); + fields.add(InternalField.KEY_FIELD); + selectFieldCombobox = new ComboBox<>(FXCollections.observableArrayList(fields)); selectFieldCombobox.setEditable(true); builder.add(selectFieldCombobox, 1, 1); formattersCombobox = new ComboBox<>(FXCollections.observableArrayList(availableFormatters)); new ViewModelListCellFactory() .withText(Formatter::getName) - .withTooltip(Formatter::getDescription) + .withStringTooltip(Formatter::getDescription) .install(formattersCombobox); EasyBind.subscribe(formattersCombobox.valueProperty(), e -> updateDescription()); builder.add(formattersCombobox, 3, 1); @@ -217,8 +217,8 @@ public boolean isDefaultSaveActions() { private FieldFormatterCleanup getFieldFormatterCleanup() { Formatter selectedFormatter = formattersCombobox.getValue(); - String fieldKey = selectFieldCombobox.getValue(); - return new FieldFormatterCleanup(fieldKey, selectedFormatter); + Field field = selectFieldCombobox.getValue(); + return new FieldFormatterCleanup(field, selectedFormatter); } class EnablementStatusListener implements ChangeListener { diff --git a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java index 4fa50ccca9c..45832985b5b 100644 --- a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java @@ -2,6 +2,7 @@ import javafx.scene.Node; +import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.gui.preview.PreviewViewer; import org.jabref.gui.undo.NamedCompound; @@ -27,7 +28,7 @@ public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { @Override public Node description() { - PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService()); + PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService(), Globals.stateManager); previewViewer.setEntry(diskEntry); return previewViewer; } diff --git a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java index fcad087163d..68b6452a1c2 100644 --- a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.collab; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.Set; @@ -16,6 +17,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,12 +45,12 @@ public EntryChangeViewModel(BibEntry memEntry, BibEntry tmpEntry, BibEntry diskE LOGGER.debug("Modified entry: " + memEntry.getCiteKeyOptional().orElse("") + "\n Modified locally: " + isModifiedLocally + " Modifications agree: " + modificationsAgree); - Set allFields = new TreeSet<>(); - allFields.addAll(memEntry.getFieldNames()); - allFields.addAll(tmpEntry.getFieldNames()); - allFields.addAll(diskEntry.getFieldNames()); + Set allFields = new TreeSet<>(Comparator.comparing(Field::getName)); + allFields.addAll(memEntry.getFields()); + allFields.addAll(tmpEntry.getFields()); + allFields.addAll(diskEntry.getFields()); - for (String field : allFields) { + for (Field field : allFields) { Optional mem = memEntry.getField(field); Optional tmp = tmpEntry.getField(field); Optional disk = diskEntry.getField(field); @@ -94,13 +96,13 @@ static class FieldChangeViewModel extends DatabaseChangeViewModel { private final BibEntry entry; private final BibEntry tmpEntry; - private final String field; + private final Field field; private final String inMem; private final String onTmp; private final String onDisk; - public FieldChangeViewModel(String field, BibEntry memEntry, BibEntry tmpEntry, String inMem, String onTmp, String onDisk) { - super(field); + public FieldChangeViewModel(Field field, BibEntry memEntry, BibEntry tmpEntry, String inMem, String onTmp, String onDisk) { + super(field.getName()); entry = memEntry; this.tmpEntry = tmpEntry; this.field = field; diff --git a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java index f8e2b88a02c..f07dcbe28c9 100644 --- a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java @@ -2,6 +2,7 @@ import javafx.scene.Node; +import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.gui.preview.PreviewViewer; import org.jabref.gui.undo.NamedCompound; @@ -44,7 +45,7 @@ public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { @Override public Node description() { - PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService()); + PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService(), Globals.stateManager); previewViewer.setEntry(memEntry); return previewViewer; } diff --git a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml index 091f3b3ab91..a2f89fa69af 100644 --- a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml +++ b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml @@ -16,7 +16,7 @@