diff --git a/.gitignore b/.gitignore index eef074f6e45..39f4c1f4ac2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,14 @@ status.md # Install4J install4j6/ +# Snap +parts/ +stage/ +prime/ +*.snap +jabref_source.tar.bz2 +snap/.snapcraft/ + # Gradle # generated when `gradlew --gui` is called ui/ @@ -23,18 +31,6 @@ ui/ jabref.xml *.sonargraph -# Snapcraft - JabRef places the files into buildres/snapcraft -snap/ - - - - - - - - - - # Created by https://www.gitignore.io/api/gradle,java,jabref,intellij,eclipse,netbeans,windows,linux,macos,node,snapcraft ### Eclipse ### diff --git a/.mailmap b/.mailmap index b8698d75865..3af3033fd28 100644 --- a/.mailmap +++ b/.mailmap @@ -142,4 +142,5 @@ Johannes Manner Dominik Traczyk Cerrianne Santos Stefan Scheffel -Stefan Gerzmann \ No newline at end of file +Stefan Gerzmann +Deepak Kumar diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c29a663c2b..651ab6ab391 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ## [Unreleased] ### Changed +- 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) - DOI/URL: General -> Optional @@ -48,14 +49,24 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We updated updated the Related Articles tab to accept JSON from the new version of the Mr. DLib service - We added an option in the preference dialog box that allows user to choose behavior after dragging and dropping files in Entry Editor. [#4356](https://github.com/JabRef/jabref/issues/4356) - We added the ability to have an export preference where previously "File"-->"Export"/"Export selected entries" would not save the user's preference[#4495](https://github.com/JabRef/jabref/issues/4495) +- We optimized the code responsible for connecting to an external database, which should lead to huge improvements in performance. +- 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 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 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 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) ### Fixed +- We fixed an issue where JabRef died silently for the user without enough inotify instances [#4874](https://github.com/JabRef/jabref/issues/4847) - We fixed an issue where corresponding groups are sometimes not highlighted when clicking on entries [#3112](https://github.com/JabRef/jabref/issues/3112) - We fixed an issue where custom exports could not be selected in the 'Export (selected) entries' dialog [#4013](https://github.com/JabRef/jabref/issues/4013) - Italic text is now rendered correctly. https://github.com/JabRef/jabref/issues/3356 @@ -67,6 +78,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where selecting a group messed up the focus of the main table / entry editor. https://github.com/JabRef/jabref/issues/3367 - We fixed an issue where composite author names were sorted incorrectly. https://github.com/JabRef/jabref/issues/2828 - We fixed an issue where commands followed by `-` didn't work. [#3805](https://github.com/JabRef/jabref/issues/3805) +- We fixed an issue where a non-existing aux file in a group made it impossible to open the library. [#4735](https://github.com/JabRef/jabref/issues/4735) - We fixed an issue where some journal names were wrongly marked as abbreviated. [#4115](https://github.com/JabRef/jabref/issues/4115) - We fixed an issue where the custom file column were sorted incorrectly. https://github.com/JabRef/jabref/issues/3119 - We fixed an issues where the entry losses focus when a field is edited and at the same time used for sorting. https://github.com/JabRef/jabref/issues/3373 @@ -80,6 +92,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where the default icon of a group was not colored correctly. - We fixed an issue where the first field in entry editor was not focused when adding a new entry. [#4024](https://github.com/JabRef/jabref/issues/4024) - We reworked the "Edit file" dialog to make it resizeable and improved the workflow for adding and editing files https://github.com/JabRef/jabref/issues/2970 +- We fixed an issue where custom name formatters were no longer found correctly. [#3531](https://github.com/JabRef/jabref/issues/3531) - We fixed an issue where the month was not shown in the preview https://github.com/JabRef/jabref/issues/3239. - Rewritten logic to detect a second jabref instance. [#4023](https://github.com/JabRef/jabref/issues/4023) - We fixed an issue where the "Convert to BibTeX-Cleanup" moved the content of the `file` field to the `pdf` field [#4120](https://github.com/JabRef/jabref/issues/4120) @@ -93,21 +106,27 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where only one PDF file could be imported [#4422](https://github.com/JabRef/jabref/issues/4422) - We fixed an issue where "Move to group" would always move the first entry in the library and not the selected [#4414](https://github.com/JabRef/jabref/issues/4414) - We fixed an issue where an older dialog appears when downloading full texts from the quality menu. [#4489](https://github.com/JabRef/jabref/issues/4489) - - +- We fixed an issue where right clicking on any entry in any database and selecting "Open folder" results in the NullPointer exception. [#4763](https://github.com/JabRef/jabref/issues/4763) +- We fixed an issue where option 'open terminal here' with custom command was passing wrong argument. [#4802](https://github.com/JabRef/jabref/issues/4802) +- We fixed an issue where ranking an entry would generate an IllegalArgumentException. [#4754](https://github.com/JabRef/jabref/issues/4754) +- 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) ### Removed - The feature to "mark entries" was removed and merged with the groups functionality. For migration, a group is created for every value of the `__markedentry` field and the entry is added to this group. - The number column was removed. +- We removed the global search feature. - We removed the coloring of cells in the maintable according to whether the field is optional/required. +- We removed the feature to find and resolve duplicate BibTeX keys (as this use case is already covered by the integrity check). - We removed a few commands from the right-click menu that are not needed often and thus don't need to be placed that prominently: - Print entry preview: available through entry preview - All commands related to marking: marking is not yet reimplemented - Set/clear/append/rename fields: available through Edit menu - Manage keywords: available through Edit menu - Copy linked files to folder: available through File menu + - Add/move/remove from group: removed completely (functionality still available through group interface) - We removed the option to change the column widths in the preferences dialog. [#4546](https://github.com/JabRef/jabref/issues/4546) @@ -136,7 +155,6 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - ## Older versions diff --git a/build.gradle b/build.gradle index 210ce86bf4b..96f7c0b065f 100644 --- a/build.gradle +++ b/build.gradle @@ -15,21 +15,19 @@ buildscript { } plugins { - id 'com.gradle.build-scan' version '1.16' - id 'com.install4j.gradle' version '7.0.9' - id 'com.github.johnrengelman.shadow' version '4.0.2' + id 'com.gradle.build-scan' version '2.0.2' + id 'com.install4j.gradle' version '7.0.10' + id 'com.github.johnrengelman.shadow' version '5.0.0' id "com.simonharrer.modernizer" version '1.6.0-1' id 'me.champeau.gradle.jmh' version '0.4.8' - id 'net.ltgt.errorprone' version '0.6.1' + id 'net.ltgt.errorprone' version '0.7.1' + id 'com.github.ben-manes.versions' version '0.21.0' id 'com.zyxist.chainsaw' version '0.3.1' - id 'com.github.ben-manes.versions' version '0.20.0' } // use the gradle build scan feature: https://scans.gradle.com/get-started -buildScan { - licenseAgreementUrl = 'https://gradle.com/terms-of-service' - licenseAgree = 'yes' -} +buildScan { termsOfServiceUrl = 'https://gradle.com/terms-of-service'; termsOfServiceAgree = 'yes' } + apply plugin: 'java' apply plugin: 'application' @@ -111,25 +109,24 @@ dependencies { compile 'com.jgoodies:jgoodies-common:1.8.1' compile 'com.jgoodies:jgoodies-forms:1.9.0' - compile 'org.apache.pdfbox:pdfbox:2.0.13' - compile 'org.apache.pdfbox:fontbox:2.0.13' - compile 'org.apache.pdfbox:xmpbox:2.0.13' + 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 group: 'org.apache.tika', name: 'tika-core', version: '1.20' // required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635 - compile 'org.bouncycastle:bcprov-jdk15on:1.60' + compile 'org.bouncycastle:bcprov-jdk15on:1.61' compile 'commons-cli:commons-cli:1.4' - // TODO: LibreOffice has a split package, temporarily removed - libreoffice "org.libreoffice:juh:5.4.2" - libreoffice "org.libreoffice:jurt:5.4.2" - libreoffice "org.libreoffice:ridl:5.4.2" - libreoffice "org.libreoffice:unoil:5.4.2" + compile "org.libreoffice:juh:6.2.2" + compile "org.libreoffice:jurt:6.2.2" + compile "org.libreoffice:ridl:6.2.2" + compile "org.libreoffice:unoil:6.2.2" compile 'io.github.java-diff-utils:java-diff-utils:4.0' - compile 'info.debatty:java-string-similarity:1.1.0' + compile 'info.debatty:java-string-similarity:1.2.1' antlr3 'org.antlr:antlr:3.5.2' compile 'org.antlr:antlr-runtime:3.5.2' @@ -137,24 +134,24 @@ dependencies { antlr4 'org.antlr:antlr4:4.7.2' compile 'org.antlr:antlr4-runtime:4.7.2' - compile 'mysql:mysql-connector-java:8.0.14' + compile 'mysql:mysql-connector-java:8.0.15' compile 'org.postgresql:postgresql:42.2.5' compile 'net.java.dev.glazedlists:glazedlists_java15:1.9.1' - compile 'com.google.guava:guava:27.0.1-jre' + compile 'com.google.guava:guava:27.1-jre' compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2' // JavaFX stuff + compile 'de.jensd:fontawesomefx-commons:8.15' compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' - compile 'de.jensd:fontawesomefx-commons:9.1.2' - compile 'de.saxsys:mvvmfx-validation:1.7.0' - compile 'de.saxsys:mvvmfx:1.7.0' + compile 'de.saxsys:mvvmfx-validation:1.8.0' + 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.9.2' + compile 'org.fxmisc.richtext:richtextfx:0.9.3' //compile 'com.sibvisions.external.jvxfx:dndtabpane:0.1' compile 'javax.inject:javax.inject:1' compile 'com.jfoenix:jfoenix:9.0.8' @@ -166,44 +163,41 @@ dependencies { 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-beta2' - compile 'org.apache.logging.log4j:log4j-slf4j18-impl:2.11.1' - compile 'org.apache.logging.log4j:log4j-jcl:2.11.1' - compile 'org.apache.logging.log4j:log4j-api:2.11.1' - compile 'org.apache.logging.log4j:log4j-core:2.11.1' + 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 'de.undercouch:citeproc-java:1.0.1' // JAX-B is considered JavaEE API and is no longer part of JavaSE (JDK 9) compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0' compile group: 'com.sun.xml.bind', name: 'jaxb-core', version: '2.3.0' + compile 'com.github.tomtung:latex2unicode_2.12:0.2.2' errorprone 'com.google.errorprone:error_prone_core:2.3.2' - compile group: 'com.microsoft.azure', name: 'applicationinsights-core', version: '2.3.0' - compile group: 'com.microsoft.azure', name: 'applicationinsights-logging-log4j2', version: '2.3.0' + 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' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.2' - testCompile 'org.junit.jupiter:junit-jupiter-params:5.3.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.2' - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.2' - testCompile 'org.junit.platform:junit-platform-launcher:1.3.2' + 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' - testCompile 'org.junit-pioneer:junit-pioneer:0.3.0' testRuntime 'org.apache.logging.log4j:log4j-core:2.11.1' - testRuntime 'org.apache.logging.log4j:log4j-jul:2.11.1' - testCompile 'org.mockito:mockito-core:2.23.4' - testCompile 'com.github.tomakehurst:wiremock:2.20.0' - testCompile 'org.assertj:assertj-swing-junit:3.8.0' + testRuntime 'org.apache.logging.log4j:log4j-jul:2.11.2' + testCompile 'org.mockito:mockito-core:2.27.0' + testCompile 'com.github.tomakehurst:wiremock:2.22.0' 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.9.3' - testCompile 'com.tngtech.archunit:archunit-junit5-api:0.9.3' + testRuntime 'com.tngtech.archunit:archunit-junit5-engine:0.10.2' + testCompile 'com.tngtech.archunit:archunit-junit5-api:0.10.2' testCompile "org.testfx:testfx-core:4.0.+" testCompile "org.testfx:testfx-junit5:4.0.+" - checkstyle 'com.puppycrawl.tools:checkstyle:8.16' + checkstyle 'com.puppycrawl.tools:checkstyle:8.19' } jacoco { @@ -214,9 +208,6 @@ dependencyUpdates { outputFormatter = "json" } -//We have to use this as long as junit-pioneer has no official release -dependencyUpdates.revision = 'integration' - // We have some dependencies which cannot be updated due to various reasons. dependencyUpdates.resolutionStrategy = { componentSelection { rules -> @@ -225,11 +216,6 @@ dependencyUpdates.resolutionStrategy = { selection.reject("Ignore SNAPSHOT releases") } } - rules.withModule("com.gradle.build-scan:com.gradle.build-scan.gradle.plugin") { ComponentSelection selection -> - if (selection.candidate.version ==~ /2.*/) { - selection.reject("Cannot be upgraded to version 2 until we upgrade to gradle 5") - } - } rules.withModule("org.controlsfx:controlsfx") { ComponentSelection selection -> if (selection.candidate.version ==~ /9.*/) { // Reject version 9 or higher selection.reject("Cannot be updated to 9.*.* until Jabref works with Java 9") @@ -351,11 +337,14 @@ task generateSearchGrammarSource(type: JavaExec) { compileJava { options.encoding = 'UTF-8' options.compilerArgs << "-Xlint:none" + //ignore annotation processor from log4j2 + options.compilerArgs += '-proc:none' } compileJava.dependsOn "generateSource" compileTestJava { options.encoding = 'UTF-8' + options.compilerArgs += '-proc:none' } javadoc { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13536770052..87b738cbd05 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0b3fb8d70b..ea13fdfd192 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.3.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/lib/AppleJavaExtensions.jar b/lib/AppleJavaExtensions.jar deleted file mode 100644 index 6659a81c69f..00000000000 Binary files a/lib/AppleJavaExtensions.jar and /dev/null differ diff --git a/buildres/snapcraft/jabref.desktop b/snap/gui/jabref.desktop similarity index 90% rename from buildres/snapcraft/jabref.desktop rename to snap/gui/jabref.desktop index ef63a896d2d..3444b73fc8a 100644 --- a/buildres/snapcraft/jabref.desktop +++ b/snap/gui/jabref.desktop @@ -4,7 +4,7 @@ GenericName=BibTeX Editor Comment=JabRef is an open source bibliography reference manager. The native file format used by JabRef is BibTeX, the standard LaTeX bibliography format. Type=Application Terminal=false -Icon=${SNAP}/meta/gui/JabRef-icon-256.png +Icon=${SNAP}/meta/gui/jabref.png Exec=jabref %U Keywords=bibtex;biblatex;latex;bibliography Categories=Office; diff --git a/buildres/snapcraft/JabRef-icon-256.png b/snap/gui/jabref.png similarity index 100% rename from buildres/snapcraft/JabRef-icon-256.png rename to snap/gui/jabref.png diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 00000000000..b26f84fef0d --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,41 @@ +name: jabref +version: "git" +version-script: cat build.gradle | grep "^version =" | cut -d'"' -f2 +#icon: snap/gui/jabref.png +summary: Bibliography manager +description: JabRef is an open source bibliography reference manager. The native file format used by JabRef is BibTeX, the standard LaTeX bibliography format. + +grade: devel +confinement: strict + +architectures: + - build-on: amd64 + - build-on: i386 + +apps: + jabref: + command: desktop-launch java -jar $SNAP/jar/JabRef-$SNAP_VERSION.jar + environment: + _JAVA_OPTIONS: "-Duser.home=$SNAP_USER_DATA" + plugs: + - desktop + - desktop-legacy + - wayland + - unity7 + - home + - opengl + - network-bind + - removable-media + +parts: + jabref: + plugin: gradle + source: . + source-type: git + stage-packages: + - openjdk-8-jre + - openjfx + - x11-utils + gradle-options: [snapJar, -xtest] + gradle-output-dir: 'build/releases' + after: [desktop-gtk2] diff --git a/snapcraft.yaml b/snapcraft.yaml deleted file mode 100644 index 0daa48c83c4..00000000000 --- a/snapcraft.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# based on https://github.com/snapcore/snapcraft/blob/master/demos/gradle/snap/snapcraft.yaml - -name: jabref - -# the version string 4.2-dev is replaced by scripts/run-snapcraft.sh with the current version provided in build.gradle -version: '4.2-dev' - -summary: Bibliography manager -icon: buildres/snapcraft/JabRef-icon-256.png -description: JabRef is an open source bibliography reference manager. The native file format used by JabRef is BibTeX, the standard LaTeX bibliography format. - -# only with the following set to stable + strict, we can do a full release - -# see https://snapcraft.io/docs/reference/channels -# stable | devel -grade: devel - -# see https://snapcraft.io/docs/reference/confinement -# strict | devmode -confinement: strict - -apps: - jabref: - command: desktop-launch java -jar $SNAP/jar/JabRef-4.2-dev.jar - plugs: [desktop, desktop-legacy, wayland, unity7, home, network-bind] - desktop: ../buildres/snapcraft/jabref.desktop - -parts: - jabref: - plugin: gradle - source: . - stage-packages: [default-jre, openjfx, x11-utils] - gradle-options: [snapJar] - gradle-output-dir: 'build/releases' - after: [desktop-gtk3] diff --git a/src/jmh/java/org/jabref/benchmarks/Benchmarks.java b/src/jmh/java/org/jabref/benchmarks/Benchmarks.java index c17b4c6e76b..a7316584eee 100644 --- a/src/jmh/java/org/jabref/benchmarks/Benchmarks.java +++ b/src/jmh/java/org/jabref/benchmarks/Benchmarks.java @@ -62,17 +62,22 @@ public void init() throws Exception { entry.setField("rnd", "2" + randomizer.nextInt()); database.insertEntry(entry); } - StringWriter outputWriter = new StringWriter(); - BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter(outputWriter, mock(SavePreferences.class)); - databaseWriter.savePartOfDatabase( - new BibDatabaseContext(database, new MetaData(), new Defaults()), database.getEntries()); - bibtexString = outputWriter.toString(); + + bibtexString = getOutputWriter().toString(); latexConversionString = "{A} \\textbf{bold} approach {\\it to} ${{\\Sigma}}{\\Delta}$ modulator \\textsuperscript{2} \\$"; htmlConversionString = "Österreich – & characters ⪢ italic"; } + private StringWriter getOutputWriter() throws IOException { + StringWriter outputWriter = new StringWriter(); + BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter(outputWriter, mock(SavePreferences.class)); + databaseWriter.savePartOfDatabase( + new BibDatabaseContext(database, new MetaData(), new Defaults()), database.getEntries()); + return outputWriter; + } + @Benchmark public ParserResult parse() throws IOException { BibtexParser parser = new BibtexParser(Globals.prefs.getImportFormatPreferences(), new DummyFileUpdateMonitor()); @@ -81,10 +86,7 @@ public ParserResult parse() throws IOException { @Benchmark public String write() throws Exception { - StringWriter outputWriter = new StringWriter(); - BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter(outputWriter, mock(SavePreferences.class)); - databaseWriter.savePartOfDatabase(new BibDatabaseContext(database, new MetaData(), new Defaults()), database.getEntries()); - return outputWriter.toString(); + return getOutputWriter().toString(); } @Benchmark diff --git a/src/main/java/org/jabref/Globals.java b/src/main/java/org/jabref/Globals.java index 1cc6fe1d7a5..1418be87eb4 100644 --- a/src/main/java/org/jabref/Globals.java +++ b/src/main/java/org/jabref/Globals.java @@ -9,6 +9,7 @@ import org.jabref.gui.ClipBoardManager; import org.jabref.gui.StateManager; import org.jabref.gui.keyboard.KeyBindingRepository; +import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.util.DefaultFileUpdateMonitor; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; @@ -57,6 +58,7 @@ public class Globals { public static StateManager stateManager = new StateManager(); public static ExporterFactory exportFactory; + public static CountingUndoManager undoManager = new CountingUndoManager(); // Key binding preferences private static KeyBindingRepository keyBindingRepository; private static DefaultFileUpdateMonitor fileUpdateMonitor; diff --git a/src/main/java/org/jabref/JabRefException.java b/src/main/java/org/jabref/JabRefException.java index 0c312fc10df..a1dd034d89e 100644 --- a/src/main/java/org/jabref/JabRefException.java +++ b/src/main/java/org/jabref/JabRefException.java @@ -33,7 +33,7 @@ public JabRefException(Throwable cause) { @Override public String getLocalizedMessage() { if (localizedMessage == null) { - LOGGER.debug("No localized message exception message defined. Falling back to getMessage()."); + LOGGER.debug("No localized exception message defined. Falling back to getMessage()."); return getMessage(); } else { return localizedMessage; diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 57214d9ef9f..66fe3694ffa 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -10,8 +10,6 @@ import javafx.stage.Stage; import org.jabref.gui.BasePanel; -import org.jabref.gui.DialogService; -import org.jabref.gui.FXDialogService; import org.jabref.gui.GUIGlobals; import org.jabref.gui.JabRefFrame; import org.jabref.gui.dialogs.BackupUIManager; @@ -43,14 +41,13 @@ public class JabRefGUI { private final boolean isBlank; private final List failed = new ArrayList<>(); private final List toOpenTab = new ArrayList<>(); - private final DialogService dialogService; private final String focusedFile; public JabRefGUI(Stage mainStage, List argsDatabases, boolean isBlank) { this.bibDatabases = argsDatabases; this.isBlank = isBlank; - this.dialogService = new FXDialogService(mainStage); + mainFrame = new JabRefFrame(mainStage); // passed file (we take the first one) should be focused focusedFile = argsDatabases.stream() @@ -60,22 +57,12 @@ public JabRefGUI(Stage mainStage, List argsDatabases, boolean isBl .orElse(Globals.prefs.get(JabRefPreferences.LAST_FOCUSED)); openWindow(mainStage); - new VersionWorker(Globals.BUILD_INFO.getVersion(), Globals.prefs.getVersionPreferences().getIgnoredVersion(), JabRefGUI.getMainFrame().getDialogService(), Globals.TASK_EXECUTOR) + new VersionWorker(Globals.BUILD_INFO.getVersion(), Globals.prefs.getVersionPreferences().getIgnoredVersion(), mainFrame.getDialogService(), Globals.TASK_EXECUTOR) .checkForNewVersionAsync(false); } private void openWindow(Stage mainStage) { - // Set antialiasing on everywhere. This only works in JRE >= 1.5. - // Or... it doesn't work, period. - // TODO test and maybe remove this! I found this commented out with no additional info ( payload@lavabit.com ) - // Enabled since JabRef 2.11 beta 4 - System.setProperty("swing.aatext", "true"); - // Default is "on". - // "lcd" instead of "on" because of http://wiki.netbeans.org/FaqFontRendering and http://docs.oracle.com/javase/6/docs/technotes/guides/2d/flags.html#aaFonts - System.setProperty("awt.useSystemAAFontSettings", "lcd"); - - // look and feel. This MUST be the first thing to do before loading any Swing-specific code! - setLookAndFeel(); + applyFontRenderingTweak(); // If the option is enabled, open the last edited libraries, if any. if (!isBlank && Globals.prefs.getBoolean(JabRefPreferences.OPEN_LAST_EDITED)) { @@ -85,7 +72,7 @@ private void openWindow(Stage mainStage) { GUIGlobals.init(); LOGGER.debug("Initializing frame"); - JabRefGUI.mainFrame = new JabRefFrame(mainStage); + mainFrame.init(); // Add all bibDatabases databases to the frame: boolean first = false; @@ -109,7 +96,7 @@ private void openWindow(Stage mainStage) { pr.getDatabase().clearSharedDatabaseID(); LOGGER.error("Connection error", e); - dialogService.showErrorDialogAndWait( + mainFrame.getDialogService().showErrorDialogAndWait( Localization.lang("Connection error"), Localization.lang("A local copy will be opened."), e); @@ -120,7 +107,7 @@ private void openWindow(Stage mainStage) { // add them to the list toOpenTab.add(pr); } else { - JabRefGUI.getMainFrame().addParserResult(pr, first); + mainFrame.addParserResult(pr, first); first = false; } } @@ -128,7 +115,7 @@ private void openWindow(Stage mainStage) { // finally add things to the currently opened tab for (ParserResult pr : toOpenTab) { - JabRefGUI.getMainFrame().addParserResult(pr, first); + mainFrame.addParserResult(pr, first); first = false; } @@ -168,14 +155,14 @@ private void openWindow(Stage mainStage) { String message = Localization.lang("Error opening file '%0'.", pr.getFile().get().getName()) + "\n" + pr.getErrorMessage(); - dialogService.showErrorDialogAndWait(Localization.lang("Error opening file"), message); + mainFrame.getDialogService().showErrorDialogAndWait(Localization.lang("Error opening file"), message); } // Display warnings, if any int tabNumber = 0; for (ParserResult pr : bibDatabases) { - ParserResultWarningDialog.showParserResultWarningDialog(pr, JabRefGUI.getMainFrame(), tabNumber++); + ParserResultWarningDialog.showParserResultWarningDialog(pr, mainFrame, tabNumber++); } // After adding the databases, go through each and see if @@ -187,9 +174,9 @@ private void openWindow(Stage mainStage) { // This is because importToOpen might have been used, which adds to // loadedDatabases, but not to getBasePanelCount() - for (int i = 0; (i < bibDatabases.size()) && (i < JabRefGUI.getMainFrame().getBasePanelCount()); i++) { + for (int i = 0; (i < bibDatabases.size()) && (i < mainFrame.getBasePanelCount()); i++) { ParserResult pr = bibDatabases.get(i); - BasePanel panel = JabRefGUI.getMainFrame().getBasePanelAt(i); + BasePanel panel = mainFrame.getBasePanelAt(i); OpenDatabaseAction.performPostOpenActions(panel, pr); } @@ -219,7 +206,7 @@ private void openLastEditedDatabases() { } if (BackupManager.checkForBackupFile(dbFile.toPath())) { - BackupUIManager.showRestoreBackupDialog(dialogService, dbFile.toPath()); + BackupUIManager.showRestoreBackupDialog(mainFrame.getDialogService(), dbFile.toPath()); } ParserResult parsedDatabase = OpenDatabase.loadDatabase(fileName, @@ -242,9 +229,9 @@ private boolean isLoaded(File fileToOpen) { return false; } - private void setLookAndFeel() { - // On Linux, Java FX fonts look blurry per default. This can be improved by using a non-default rendering - // setting. See https://github.com/woky/javafx-hates-linux + private void applyFontRenderingTweak() { + // On Linux, Java FX fonts look blurry per default. This can be improved by using a non-default rendering setting. + // See https://github.com/woky/javafx-hates-linux if (Globals.prefs.getBoolean(JabRefPreferences.FX_FONT_RENDERING_TWEAK)) { System.setProperty("prism.text", "t2k"); System.setProperty("prism.lcdtext", "true"); @@ -254,9 +241,4 @@ private void setLookAndFeel() { public static JabRefFrame getMainFrame() { return mainFrame; } - - // Only used for testing, other than that do NOT set the mainFrame... - public static void setMainFrame(JabRefFrame mainFrame) { - JabRefGUI.mainFrame = mainFrame; - } } diff --git a/src/main/java/org/jabref/JabRefMain.java b/src/main/java/org/jabref/JabRefMain.java index 249c97f8251..62758e9c9f0 100644 --- a/src/main/java/org/jabref/JabRefMain.java +++ b/src/main/java/org/jabref/JabRefMain.java @@ -2,14 +2,13 @@ import java.net.Authenticator; -import javax.swing.JFrame; -import javax.swing.JOptionPane; - import javafx.application.Application; import javafx.application.Platform; +import javafx.scene.control.Alert; import javafx.stage.Stage; import org.jabref.cli.ArgumentProcessor; +import org.jabref.gui.FXDialog; import org.jabref.gui.remote.JabRefMessageHandler; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; @@ -89,11 +88,11 @@ public void stop() { /** * Tests if we are running an acceptable Java and terminates JabRef when we are sure the version is not supported. * This test uses the requirements for the Java version as specified in gradle.build. It is possible to - * define a minimum version including the built number and to indicate whether Java 9 can be use (which it currently + * define a minimum version including the built number and to indicate whether Java 9 can be used (which it currently * can't). It tries to compare this version number to the version of the currently running JVM. The check is * optimistic and will rather return true even if we could not exactly determine the version. *

- * Note: Users with an very old version like 1.6 will not profit from this since class versions are incompatible and + * Note: Users with a very old version like 1.6 will not profit from this since class versions are incompatible and * JabRef won't even start. Currently, JabRef won't start with Java 9 either, but the warning that it cannot be used * with this version is helpful anyway to prevent users to update from an old 1.8 directly to version 9. Additionally, * we soon might have a JabRef that does start with Java 9 but is not perfectly compatible. Therefore, we should leave @@ -119,9 +118,10 @@ private static void ensureCorrectJavaVersion() { versionError.append("\n"); versionError.append(Localization.lang("Note that currently, JabRef does not run with Java 9.")); } - final JFrame frame = new JFrame(); - JOptionPane.showMessageDialog(null, versionError, Localization.lang("Error"), JOptionPane.ERROR_MESSAGE); - frame.dispose(); + + FXDialog alert = new FXDialog(Alert.AlertType.ERROR, Localization.lang("Error"), true); + alert.setHeaderText(null); + alert.setContentText(versionError.toString()); // We exit on Java 9 error since this will definitely not work if (java9Fail) { @@ -141,6 +141,8 @@ private static boolean handleMultipleAppInstances(String[] args) { // So we assume it's all taken care of, and quit. LOGGER.info(Localization.lang("Arguments passed on to running JabRef instance. Shutting down.")); return false; + } else { + LOGGER.warn("Could not communicate with other running JabRef instance."); } } else { // We are alone, so we start the server @@ -161,7 +163,7 @@ private static void applyPreferences(JabRefPreferences preferences) { // Read list(s) of journal names and abbreviations Globals.journalAbbreviationLoader = new JournalAbbreviationLoader(); - /* Build list of Import and Export formats */ + // 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), @@ -171,7 +173,7 @@ private static void applyPreferences(JabRefPreferences preferences) { // Initialize protected terms loader Globals.protectedTermsLoader = new ProtectedTermsLoader(Globals.prefs.getProtectedTermsPreferences()); - // override used newline character with the one stored in the preferences + // Override used newline character with the one stored in the preferences // The preferences return the system newline character sequence as default OS.NEWLINE = Globals.prefs.get(JabRefPreferences.NEWLINE); } diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index f97a582daab..56a4de65bde 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -13,7 +13,9 @@ import org.jabref.Globals; import org.jabref.JabRefException; -import org.jabref.gui.externalfiles.AutoSetLinks; +import org.jabref.gui.externalfiles.AutoSetFileLinksUtil; +import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.undo.NamedCompound; import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; import org.jabref.logic.exporter.AtomicFileWriter; import org.jabref.logic.exporter.BibDatabaseWriter; @@ -496,7 +498,8 @@ private void automaticallySetFileLinks(List loaded) { for (ParserResult parserResult : loaded) { BibDatabase database = parserResult.getDatabase(); LOGGER.info(Localization.lang("Automatically setting file links")); - AutoSetLinks.autoSetLinks(database.getEntries(), parserResult.getDatabaseContext()); + AutoSetFileLinksUtil util = new AutoSetFileLinksUtil(parserResult.getDatabaseContext(), Globals.prefs.getFilePreferences(), Globals.prefs.getAutoLinkPreferences(), ExternalFileTypes.getInstance()); + util.linkAssociatedFiles(database.getEntries(), new NamedCompound("")); } } diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index ec78513a06b..642fe8dcf88 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -18,7 +18,7 @@ -jr-white: #ffffff; -jr-gray-0: #f2f2f2; - -jr-gray-1: #e6e6e6; + -jr-gray-1: #dddddd; -jr-gray-2: #808080; -jr-gray-3: #404040; -jr-black: #000; @@ -70,7 +70,7 @@ -jr-error: -jr-light-red; /* Color for the small group view indicator for the number of hits */ - -jr-group-hits-bg: derive(-jr-sidepane-background, -5%); + -jr-group-hits-bg: derive(-jr-sidepane-background, -50%); -jr-group-hits-fg: ladder( -jr-group-hits-bg, -fx-light-text-color 45%, @@ -84,8 +84,8 @@ -jr-tooltip-fg: -jr-black; /* Finally, some specific jr styles that depend on -fx definitions in *this* style */ - -jr-sidepane-background: -jr-gray-0; - -jr-sidepane-header-background: -jr-gray-0; + -jr-sidepane-background: -jr-gray-1; + -jr-sidepane-header-background: -jr-gray-1; -jr-sidepane-header-color: -jr-theme-text; /* Specs for the scrollbars */ @@ -116,7 +116,7 @@ */ -fx-control-inner-background: derive(-fx-base, 95%); /* Version of -fx-control-inner-background for alternative rows */ - -fx-control-inner-background-alt: derive(-fx-control-inner-background, -2%); + -fx-control-inner-background-alt: derive(-fx-control-inner-background, -6%); /* One of these colors will be chosen based upon a ladder calculation * that uses the brightness of a background color. Instead of using these @@ -364,6 +364,11 @@ -fx-fill: white; } +.toggle-button:selected.icon-button:selected { + -fx-background-color: transparent; + -fx-fill: -jr-selected; +} + .icon-buttonNoSpaceBottom { -fx-padding: 0.5em 0.5em -0.1em 0.5em; } @@ -818,14 +823,14 @@ .separator:horizontal .line { -fx-border-color: -jr-separator; - -fx-border-width: 0; - -fx-border-insets: 1 0 0 0; + -fx-border-width: 0.3; + -fx-border-insets: 1 15 0 20; } .separator:vertical .line { -fx-border-color: -jr-separator; -fx-border-width: 1; - -fx-border-insets: 0 0 0 1; + -fx-border-insets: 5 15 5 15; } .mainToolbar { @@ -975,3 +980,55 @@ We want to have a look that matches our icons in the tool-bar */ .color-palette-region .button { -fx-border-width: 0px; } + +.bibEntry { + +} + +.bibEntry .type { + -fx-font-size: 110%; +} + +.bibEntry .title { + -fx-font-size: 110%; + -fx-font-weight: bold; +} + +.bibEntry .year { + -fx-font-size: 101%; + -fx-font-weight: bold; +} + +.bibEntry .journal { + -fx-font-size: 101%; +} + +.bibEntry .authors { + -fx-font-size: 101%; +} + +.bibEntry .summary { + -fx-padding: 1ex 0ex 0ex 0ex; +} + +.warning-icon { + -fx-fill: -jr-warn; +} + +.error-icon { + -fx-text-fill: -jr-error; + -fx-fill: -jr-error; +} + +.tooltip-warning { + -fx-background-color: -jr-warn; +} + +.tooltip-error { + -fx-background-color: -jr-error; +} + +.sectionHeader { + -fx-font-size: 1.5em; + -fx-padding: 1em 0em 1em 0em; +} diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 777c06eaf6f..0fbe1e98e9d 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1,6 +1,5 @@ package org.jabref.gui; -import java.io.File; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; @@ -25,7 +24,6 @@ import javafx.scene.Node; import javafx.scene.control.ScrollPane; import javafx.scene.control.SplitPane; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.StackPane; import org.jabref.Globals; @@ -40,10 +38,8 @@ import org.jabref.gui.autocompleter.AutoCompleteUpdater; import org.jabref.gui.autocompleter.PersonNameSuggestionProvider; import org.jabref.gui.autocompleter.SuggestionProviders; -import org.jabref.gui.bibtexkeypattern.SearchFixDuplicateLabels; import org.jabref.gui.collab.DatabaseChangeMonitor; -import org.jabref.gui.collab.FileUpdatePanel; -import org.jabref.gui.contentselector.ContentSelectorDialog; +import org.jabref.gui.collab.DatabaseChangePane; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.edit.ReplaceStringAction; import org.jabref.gui.entryeditor.EntryEditor; @@ -54,7 +50,6 @@ import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.filelist.FileListEntry; import org.jabref.gui.filelist.FileListTableModel; -import org.jabref.gui.groups.GroupAddRemoveDialog; import org.jabref.gui.icon.JabRefIcon; import org.jabref.gui.importer.actions.AppendDatabaseAction; import org.jabref.gui.journals.AbbreviateAction; @@ -68,7 +63,6 @@ import org.jabref.gui.specialfields.SpecialFieldViewModel; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableChangeType; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.undo.UndoableInsertEntry; import org.jabref.gui.undo.UndoableRemoveEntry; @@ -141,6 +135,7 @@ public class BasePanel extends StackPane { // As most enums, this must not be null private BasePanelMode mode = BasePanelMode.SHOWING_NOTHING; private SplitPane splitPane; + private DatabaseChangePane changePane; private boolean saving; // AutoCompleter used in the search bar @@ -150,7 +145,6 @@ public class BasePanel extends StackPane { // Used to track whether the base has changed since last save. private BibEntry showing; - private StringDialog stringDialog; private SuggestionProviders suggestionProviders; @SuppressWarnings({"FieldCanBeLocal", "unused"}) private Subscription dividerPositionSubscription; @@ -190,19 +184,6 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas // ensure that all entry changes mark the panel as changed this.bibDatabaseContext.getDatabase().registerListener(this); - Optional file = bibDatabaseContext.getDatabaseFile(); - if (file.isPresent()) { - // Register so we get notifications about outside changes to the file. - changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), this)); - } else { - if (bibDatabaseContext.getDatabase().hasEntries()) { - // if the database is not empty and no file is assigned, - // the database came from an import and has to be treated somehow - // -> mark as changed - this.baseChanged = true; - } - } - this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences(), Globals.getFileUpdateMonitor(), dialogService, externalFileTypes, Globals.TASK_EXECUTOR); @@ -269,12 +250,12 @@ public JabRefFrame frame() { } public void output(String s) { - frame.output(s); + dialogService.notify(s); } private void setupActions() { SaveDatabaseAction saveAction = new SaveDatabaseAction(this, Globals.prefs); - CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs); + CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs, Globals.TASK_EXECUTOR); actions.put(Actions.UNDO, undoAction); actions.put(Actions.REDO, redoAction); @@ -308,17 +289,6 @@ private void setupActions() { actions.put(Actions.SELECT_ALL, mainTable.getSelectionModel()::selectAll); - // The action for opening the string editor - actions.put(Actions.EDIT_STRINGS, () -> { - if (stringDialog == null) { - StringDialog form = new StringDialog(frame, BasePanel.this, bibDatabaseContext.getDatabase()); - form.setVisible(true); - stringDialog = form; - } else { - stringDialog.setVisible(true); - } - }); - // The action for auto-generating keys. actions.put(Actions.MAKE_KEY, new GenerateBibtexKeyAction(this, frame.getDialogService())); @@ -374,48 +344,43 @@ private void setupActions() { actions.put(Actions.MERGE_WITH_FETCHED_ENTRY, new MergeWithFetchedEntryAction(this, frame.getDialogService())); - actions.put(Actions.REPLACE_ALL, ()-> (new ReplaceStringAction(this)).execute()); + 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(); + .withPreviewPanelEnabled(enabled) + .build(); Globals.prefs.storePreviewPreferences(newPreviewPreferences); - DefaultTaskExecutor.runInJavaFXThread(() -> setPreviewActiveBasePanels(enabled)); + setPreviewActive(enabled); }); actions.put(Actions.NEXT_PREVIEW_STYLE, this::nextPreviewStyle); actions.put(Actions.PREVIOUS_PREVIEW_STYLE, this::previousPreviewStyle); - actions.put(Actions.MANAGE_SELECTORS, () -> { - ContentSelectorDialog csd = new ContentSelectorDialog(frame, BasePanel.this, false, null); - csd.setVisible(true); - }); - actions.put(Actions.SEND_AS_EMAIL, new SendAsEMailAction(frame)); actions.put(Actions.WRITE_XMP, new WriteXMPAction(this)::execute); @@ -424,12 +389,6 @@ private void setupActions() { actions.put(Actions.ABBREVIATE_MEDLINE, new AbbreviateAction(this, false)); actions.put(Actions.UNABBREVIATE, new UnabbreviateAction(this)); - actions.put(Actions.RESOLVE_DUPLICATE_KEYS, new SearchFixDuplicateLabels(this)); - - actions.put(Actions.ADD_TO_GROUP, new GroupAddRemoveDialog(this, true, false)); - actions.put(Actions.REMOVE_FROM_GROUP, new GroupAddRemoveDialog(this, false, false)); - actions.put(Actions.MOVE_TO_GROUP, new GroupAddRemoveDialog(this, true, true)); - actions.put(Actions.DOWNLOAD_FULL_TEXT, new FindFullTextAction(this)::execute); } @@ -439,7 +398,8 @@ private void setupActions() { * @param outputFormat the desired {@link CitationStyleOutputFormat} */ private void copyCitationToClipboard(CitationStyleOutputFormat outputFormat) { - new CitationStyleToClipboardWorker(this, outputFormat).execute(); + CitationStyleToClipboardWorker worker = new CitationStyleToClipboardWorker(this, outputFormat, dialogService, Globals.clipboardManager, Globals.prefs.getPreviewPreferences()); + worker.copyCitationStyleToClipboard(Globals.TASK_EXECUTOR); } /** @@ -481,7 +441,7 @@ private void delete(boolean cut, List entries) { getUndoManager().addEdit(compound); markBaseChanged(); - frame.output(formatOutputMessage(cut ? Localization.lang("Cut") : Localization.lang("Deleted"), entries.size())); + this.output(formatOutputMessage(cut ? Localization.lang("Cut") : Localization.lang("Deleted"), entries.size())); // prevent the main table from loosing focus mainTable.requestFocus(); @@ -496,9 +456,9 @@ private void copyTitle() { if (!selectedBibEntries.isEmpty()) { // Collect all non-null titles. List titles = selectedBibEntries.stream() - .filter(bibEntry -> bibEntry.getTitle().isPresent()) - .map(bibEntry -> bibEntry.getTitle().get()) - .collect(Collectors.toList()); + .filter(bibEntry -> bibEntry.getTitle().isPresent()) + .map(bibEntry -> bibEntry.getTitle().get()) + .collect(Collectors.toList()); if (titles.isEmpty()) { output(Localization.lang("None of the selected entries have titles.")); @@ -530,8 +490,8 @@ private void copyCiteKey() { String sb = String.join(",", keys); String citeCommand = Optional.ofNullable(Globals.prefs.get(JabRefPreferences.CITE_COMMAND)) - .filter(cite -> cite.contains("\\")) // must contain \ - .orElse("\\cite"); + .filter(cite -> cite.contains("\\")) // must contain \ + .orElse("\\cite"); Globals.clipboardManager.setContent(citeCommand + "{" + sb + '}'); if (keys.size() == bes.size()) { @@ -575,7 +535,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; @@ -609,13 +569,12 @@ private void copyKeyAndTitle() { } private void openExternalFile() { + final List selectedEntries = mainTable.getSelectedEntries(); + if (selectedEntries.size() != 1) { + output(Localization.lang("This operation requires exactly one item to be selected.")); + return; + } JabRefExecutorService.INSTANCE.execute(() -> { - final List selectedEntries = mainTable.getSelectedEntries(); - if (selectedEntries.size() != 1) { - output(Localization.lang("This operation requires exactly one item to be selected.")); - return; - } - final BibEntry entry = selectedEntries.get(0); if (!entry.hasField(FieldName.FILE)) { // no bibtex field @@ -719,12 +678,12 @@ private void createMainTable() { // Update entry editor and preview according to selected entries mainTable.addSelectionListener(event -> mainTable.getSelectedEntries() - .stream() - .findFirst() - .ifPresent(entry -> { - preview.setEntry(entry); - entryEditor.setEntry(entry); - })); + .stream() + .findFirst() + .ifPresent(entry -> { + preview.setEntry(entry); + entryEditor.setEntry(entry); + })); // TODO: Register these actions globally /* @@ -797,13 +756,9 @@ public void setupMainPanel() { createMainTable(); ScrollPane pane = mainTable.getPane(); - AnchorPane anchorPane = new AnchorPane(pane); - AnchorPane.setBottomAnchor(pane, 0.0); - AnchorPane.setTopAnchor(pane, 0.0); - AnchorPane.setLeftAnchor(pane, 0.0); - AnchorPane.setRightAnchor(pane, 0.0); - splitPane.getItems().add(anchorPane); - this.getChildren().setAll(splitPane); + pane.setFitToHeight(true); + pane.setFitToWidth(true); + splitPane.getItems().add(pane); // Set up name autocompleter for search: instantiateSearchAutoCompleter(); @@ -814,8 +769,24 @@ public void setupMainPanel() { // Saves the divider position as soon as it changes // We need to keep a reference to the subscription, otherwise the binding gets garbage collected dividerPositionSubscription = EasyBind.monadic(Bindings.valueAt(splitPane.getDividers(), 0)) - .flatMap(SplitPane.Divider::positionProperty) - .subscribe((observable, oldValue, newValue) -> saveDividerLocation(newValue)); + .flatMap(SplitPane.Divider::positionProperty) + .subscribe((observable, oldValue, newValue) -> saveDividerLocation(newValue)); + + // Add changePane in case a file is present - otherwise just add the splitPane to the panel + Optional file = bibDatabaseContext.getDatabasePath(); + if (file.isPresent()) { + // create changeMonitor and changePane so we get notifications about outside changes to the file. + resetChangeMonitorAndChangePane(); + } else { + if (bibDatabaseContext.getDatabase().hasEntries()) { + // if the database is not empty and no file is assigned, + // the database came from an import and has to be treated somehow + // -> mark as changed + this.baseChanged = true; + } + changePane = null; + getChildren().add(splitPane); + } } /** @@ -846,18 +817,6 @@ private void instantiateSearchAutoCompleter() { } } - public void assureStringDialogNotEditing() { - if (stringDialog != null) { - stringDialog.assureNotEditing(); - } - } - - public void updateStringDialog() { - if (stringDialog != null) { - stringDialog.refreshTable(); - } - } - private void adjustSplitter() { if (mode == BasePanelMode.SHOWING_PREVIEW) { splitPane.setDividerPositions(Globals.prefs.getPreviewPreferences().getPreviewPanelDividerPosition().doubleValue()); @@ -878,17 +837,13 @@ public EntryEditor getEntryEditor() { * @param entry The entry to edit. */ public void showAndEdit(BibEntry entry) { - DefaultTaskExecutor.runInJavaFXThread(() -> { + showBottomPane(BasePanelMode.SHOWING_EDITOR); - showBottomPane(BasePanelMode.SHOWING_EDITOR); - - if (entry != getShowing()) { - entryEditor.setEntry(entry); - showing = entry; - } - entryEditor.requestFocus(); - - }); + if (entry != getShowing()) { + entryEditor.setEntry(entry); + showing = entry; + } + entryEditor.requestFocus(); } private void showBottomPane(BasePanelMode newMode) { @@ -945,9 +900,9 @@ public void previousPreviewStyle() { private void cyclePreview(int newPosition) { PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() - .getBuilder() - .withPreviewCyclePosition(newPosition) - .build(); + .getBuilder() + .withPreviewCyclePosition(newPosition) + .build(); Globals.prefs.storePreviewPreferences(previewPreferences); preview.updateLayout(previewPreferences); @@ -1054,43 +1009,6 @@ public BibDatabase getDatabase() { return bibDatabaseContext.getDatabase(); } - public void stringsClosing() { - stringDialog = null; - } - - public void changeTypeOfSelectedEntries(String newType) { - List bes = mainTable.getSelectedEntries(); - changeType(bes, newType); - } - - private void changeType(List entries, String newType) { - if ((entries == null) || (entries.isEmpty())) { - LOGGER.error("At least one entry must be selected to be able to change the type."); - return; - } - - if (entries.size() > 1) { - boolean proceed = dialogService.showConfirmationDialogAndWait(Localization.lang("Change entry type"), Localization.lang("Multiple entries selected. Do you want to change the type of all these to '%0'?")); - if (!proceed) { - return; - } - } - - NamedCompound compound = new NamedCompound(Localization.lang("Change entry type")); - for (BibEntry entry : entries) { - compound.addEdit(new UndoableChangeType(entry, entry.getType(), newType)); - DefaultTaskExecutor.runInJavaFXThread(() -> { - entry.setType(newType); - }); - } - - output(formatOutputMessage(Localization.lang("Changed type to '%0' for", newType), entries.size())); - compound.end(); - getUndoManager().addEdit(compound); - markBaseChanged(); - updateEntryEditorIfShowing(); - } - public boolean showDeleteConfirmationDialog(int numberOfEntries) { if (Globals.prefs.getBoolean(JabRefPreferences.CONFIRM_DELETE)) { String title = Localization.lang("Delete entry"); @@ -1105,11 +1023,11 @@ 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; } @@ -1125,29 +1043,20 @@ private void saveDividerLocation(Number position) { if (mode == BasePanelMode.SHOWING_PREVIEW) { PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() - .getBuilder() - .withPreviewPanelDividerPosition(position) - .build(); + .getBuilder() + .withPreviewPanelDividerPosition(position) + .build(); Globals.prefs.storePreviewPreferences(previewPreferences); } else if (mode == BasePanelMode.SHOWING_EDITOR) { preferences.setEntryEditorDividerPosition(position.doubleValue()); } } - /** * Perform necessary cleanup when this BasePanel is closed. */ public void cleanUp() { changeMonitor.ifPresent(DatabaseChangeMonitor::unregister); - - // Check if there is a FileUpdatePanel for this BasePanel being shown. If so remove it: - if (sidePaneManager.isComponentVisible(SidePaneType.FILE_UPDATE_NOTIFICATION)) { - FileUpdatePanel fup = (FileUpdatePanel) sidePaneManager.getComponent(SidePaneType.FILE_UPDATE_NOTIFICATION); - if (fup.getPanel() == this) { - sidePaneManager.hide(SidePaneType.FILE_UPDATE_NOTIFICATION); - } - } } /** @@ -1164,10 +1073,6 @@ public BibDatabaseContext getBibDatabaseContext() { return this.bibDatabaseContext; } - public boolean isUpdatedExternally() { - return changeMonitor.map(DatabaseChangeMonitor::hasBeenModifiedExternally).orElse(false); - } - public void markExternalChangesAsResolved() { changeMonitor.ifPresent(DatabaseChangeMonitor::markExternalChangesAsResolved); } @@ -1200,15 +1105,6 @@ public String formatOutputMessage(String start, int count) { return String.format("%s %d %s.", start, count, (count > 1 ? Localization.lang("entries") : Localization.lang("entry"))); } - /** - * Set the preview active state for all BasePanel instances. - */ - private void setPreviewActiveBasePanels(boolean enabled) { - for (int i = 0; i < frame.getTabbedPane().getTabs().size(); i++) { - frame.getBasePanelAt(i).setPreviewActive(enabled); - } - } - private void setPreviewActive(boolean enabled) { if (enabled) { showPreview(); @@ -1250,19 +1146,19 @@ public FileAnnotationCache getAnnotationCache() { return annotationCache; } - public void resetChangeMonitor() { + public void resetChangeMonitorAndChangePane() { changeMonitor.ifPresent(DatabaseChangeMonitor::unregister); - changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), this)); + changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext, Globals.getFileUpdateMonitor(), Globals.TASK_EXECUTOR)); + + changePane = new DatabaseChangePane(splitPane, bibDatabaseContext, changeMonitor.get()); + + this.getChildren().setAll(changePane); } public void updateTimeStamp() { changeMonitor.ifPresent(DatabaseChangeMonitor::markAsSaved); } - public Path getTempFile() { - return changeMonitor.map(DatabaseChangeMonitor::getTempFile).orElse(null); - } - public void copy() { mainTable.copy(); } @@ -1395,10 +1291,10 @@ public void action() { try { getUndoManager().undo(); markBaseChanged(); - frame.output(Localization.lang("Undo")); + output(Localization.lang("Undo")); } catch (CannotUndoException ex) { LOGGER.warn("Nothing to undo", ex); - frame.output(Localization.lang("Nothing to undo") + '.'); + output(Localization.lang("Nothing to undo") + '.'); } markChangedOrUnChanged(); @@ -1441,8 +1337,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) { @@ -1466,9 +1362,9 @@ public void action() { try { getUndoManager().redo(); markBaseChanged(); - frame.output(Localization.lang("Redo")); + output(Localization.lang("Redo")); } catch (CannotRedoException ex) { - frame.output(Localization.lang("Nothing to redo") + '.'); + output(Localization.lang("Nothing to redo") + '.'); } markChangedOrUnChanged(); diff --git a/src/main/java/org/jabref/gui/DefaultInjector.java b/src/main/java/org/jabref/gui/DefaultInjector.java index e94e6fe8697..ed9963b55c5 100644 --- a/src/main/java/org/jabref/gui/DefaultInjector.java +++ b/src/main/java/org/jabref/gui/DefaultInjector.java @@ -2,10 +2,14 @@ import java.util.function.Function; +import javax.swing.undo.UndoManager; + import org.jabref.Globals; +import org.jabref.JabRefGUI; import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.journals.JournalAbbreviationLoader; +import org.jabref.logic.protectedterms.ProtectedTermsLoader; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.PreferencesService; @@ -25,7 +29,7 @@ public class DefaultInjector implements PresenterFactory { */ private static Object createDependency(Class clazz) { if (clazz == DialogService.class) { - return new FXDialogService(); + return JabRefGUI.getMainFrame().getDialogService(); } else if (clazz == TaskExecutor.class) { return Globals.TASK_EXECUTOR; } else if (clazz == PreferencesService.class) { @@ -38,8 +42,12 @@ private static Object createDependency(Class clazz) { return Globals.stateManager; } else if (clazz == FileUpdateMonitor.class) { return Globals.getFileUpdateMonitor(); + } else if (clazz == ProtectedTermsLoader.class) { + return Globals.protectedTermsLoader; } else if (clazz == ClipBoardManager.class) { return Globals.clipboardManager; + } else if (clazz == UndoManager.class) { + return Globals.undoManager; } else { try { return clazz.newInstance(); diff --git a/src/main/java/org/jabref/gui/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/DuplicateResolverDialog.java index cb34df3d202..a56da356f6f 100644 --- a/src/main/java/org/jabref/gui/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/DuplicateResolverDialog.java @@ -12,10 +12,13 @@ import org.jabref.gui.util.BaseDialog; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; public class DuplicateResolverDialog extends BaseDialog { + private final BibDatabaseContext database; + public enum DuplicateResolverType { DUPLICATE_SEARCH, IMPORT_CHECK, @@ -32,12 +35,11 @@ public enum DuplicateResolverResult { BREAK } - private final JabRefFrame frame; private MergeEntries me; - public DuplicateResolverDialog(JabRefFrame frame, BibEntry one, BibEntry two, DuplicateResolverType type) { - this.frame = frame; + public DuplicateResolverDialog(BibEntry one, BibEntry two, DuplicateResolverType type, BibDatabaseContext database) { this.setTitle(Localization.lang("Possible duplicate entries")); + this.database = database; init(one, two, type); } @@ -61,14 +63,14 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { first = new ButtonType(Localization.lang("Keep left"), ButtonData.APPLY); second = new ButtonType(Localization.lang("Keep right"), ButtonData.APPLY); both = new ButtonType(Localization.lang("Keep both"), ButtonData.APPLY); - me = new MergeEntries(one, two, frame.getCurrentBasePanel().getBibDatabaseContext().getMode()); + me = new MergeEntries(one, two, database.getMode()); break; case INSPECTION: first = new ButtonType(Localization.lang("Remove old entry"), ButtonData.APPLY); second = new ButtonType(Localization.lang("Remove entry from import"), ButtonData.APPLY); both = new ButtonType(Localization.lang("Keep both"), ButtonData.APPLY); me = new MergeEntries(one, two, Localization.lang("Old entry"), - Localization.lang("From import"), frame.getCurrentBasePanel().getBibDatabaseContext().getMode()); + Localization.lang("From import"), database.getMode()); break; case DUPLICATE_SEARCH_WITH_EXACT: first = new ButtonType(Localization.lang("Keep left"), ButtonData.APPLY); @@ -77,14 +79,14 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { removeExactVisible = true; - me = new MergeEntries(one, two, frame.getCurrentBasePanel().getBibDatabaseContext().getMode()); + me = new MergeEntries(one, two, database.getMode()); break; default: first = new ButtonType(Localization.lang("Import and remove old entry"), ButtonData.APPLY); second = new ButtonType(Localization.lang("Do not import entry"), ButtonData.APPLY); both = new ButtonType(Localization.lang("Import and keep old entry"), ButtonData.APPLY); me = new MergeEntries(one, two, Localization.lang("Old entry"), - Localization.lang("From import"), frame.getCurrentBasePanel().getBibDatabaseContext().getMode()); + Localization.lang("From import"), database.getMode()); break; } if (removeExactVisible) { @@ -114,7 +116,7 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { getDialogPane().setContent(borderPane); Button helpButton = (Button) this.getDialogPane().lookupButton(help); - helpButton.setOnAction(evt -> helpCommand.getCommand().execute()); + helpButton.setOnAction(evt -> helpCommand.execute()); } public BibEntry getMergedEntry() { diff --git a/src/main/java/org/jabref/gui/DuplicateSearch.java b/src/main/java/org/jabref/gui/DuplicateSearch.java index 476b3f70276..0db4c5df1c2 100644 --- a/src/main/java/org/jabref/gui/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/DuplicateSearch.java @@ -122,12 +122,12 @@ private DuplicateSearchResult verifyDuplicates() { } private void askResolveStrategy(DuplicateSearchResult result, BibEntry first, BibEntry second, DuplicateResolverType resolverType) { - DuplicateResolverDialog dialog = new DuplicateResolverDialog(frame, first, second, resolverType); + DuplicateResolverDialog dialog = new DuplicateResolverDialog(first, second, resolverType, frame.getCurrentBasePanel().getBibDatabaseContext()); DuplicateResolverResult resolverResult = dialog.showAndWait().orElse(DuplicateResolverResult.BREAK); if ((resolverResult == DuplicateResolverResult.KEEP_LEFT) - || (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT)) { + || (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT)) { result.remove(second); if (resolverResult == DuplicateResolverResult.AUTOREMOVE_EXACT) { autoRemoveExactDuplicates.set(true); // Remember choice @@ -167,7 +167,7 @@ private void handleDuplicates(DuplicateSearchResult result) { } dialogService.notify(Localization.lang("Duplicates found") + ": " + duplicateCount.get() + ' ' - + Localization.lang("pairs processed") + ": " + result.getDuplicateCount()); + + Localization.lang("pairs processed") + ": " + result.getDuplicateCount()); compoundEdit.end(); panel.getUndoManager().addEdit(compoundEdit); diff --git a/src/main/java/org/jabref/gui/EntryType.fxml b/src/main/java/org/jabref/gui/EntryType.fxml index 7fb864fdf78..0ed5f37b502 100644 --- a/src/main/java/org/jabref/gui/EntryType.fxml +++ b/src/main/java/org/jabref/gui/EntryType.fxml @@ -12,41 +12,43 @@ - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - @@ -56,11 +58,11 @@ - - + + - - + + diff --git a/src/main/java/org/jabref/gui/EntryTypeViewModel.java b/src/main/java/org/jabref/gui/EntryTypeViewModel.java index d023aa48900..766d449f6c4 100644 --- a/src/main/java/org/jabref/gui/EntryTypeViewModel.java +++ b/src/main/java/org/jabref/gui/EntryTypeViewModel.java @@ -1,6 +1,5 @@ package org.jabref.gui; -import java.util.Arrays; import java.util.Optional; import javafx.beans.property.BooleanProperty; @@ -15,7 +14,6 @@ import javafx.concurrent.Task; import javafx.concurrent.Worker; -import org.jabref.gui.importer.ImportInspectionDialog; import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; import org.jabref.logic.importer.FetcherException; @@ -138,18 +136,30 @@ public void runFetcherWorker() { fetcherWorker.setOnSucceeded(evt -> { Optional result = fetcherWorker.getValue(); if (result.isPresent()) { - final BibEntry bibEntry = result.get(); - if ((DuplicateCheck.containsDuplicate(basePanel.getDatabase(), bibEntry, basePanel.getBibDatabaseContext().getMode()).isPresent())) { - //If there are duplicates starts ImportInspectionDialog - ImportInspectionDialog diag = new ImportInspectionDialog(basePanel.frame(), basePanel, Localization.lang("Import"), false); - diag.addEntries(Arrays.asList(bibEntry)); - diag.entryListComplete(); - diag.setVisible(true); - diag.toFront(); + final BibEntry entry = result.get(); + Optional duplicate = DuplicateCheck.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)) { + case KEEP_LEFT: + basePanel.getDatabase().removeEntry(duplicate.get()); + basePanel.getDatabase().insertEntry(entry); + break; + case KEEP_BOTH: + basePanel.getDatabase().insertEntry(entry); + break; + case KEEP_MERGE: + basePanel.getDatabase().removeEntry(duplicate.get()); + basePanel.getDatabase().insertEntry(dialog.getMergedEntry()); + break; + default: + // Do nothing + break; + } } else { // Regenerate CiteKey of imported BibEntry - new BibtexKeyGenerator(basePanel.getBibDatabaseContext(), prefs.getBibtexKeyPatternPreferences()).generateAndSetKey(bibEntry); - basePanel.insertEntry(bibEntry); + new BibtexKeyGenerator(basePanel.getBibDatabaseContext(), prefs.getBibtexKeyPatternPreferences()).generateAndSetKey(entry); + basePanel.insertEntry(entry); } searchSuccesfulProperty.set(true); diff --git a/src/main/java/org/jabref/gui/FXDialogService.java b/src/main/java/org/jabref/gui/FXDialogService.java index 0d6bc1fecd0..579b4de8bdd 100644 --- a/src/main/java/org/jabref/gui/FXDialogService.java +++ b/src/main/java/org/jabref/gui/FXDialogService.java @@ -24,21 +24,27 @@ import javafx.scene.control.ChoiceDialog; import javafx.scene.control.DialogPane; import javafx.scene.control.TextInputDialog; +import javafx.scene.layout.Pane; import javafx.scene.layout.Region; import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; import javafx.stage.Stage; import javafx.stage.Window; +import javafx.util.Duration; -import org.jabref.JabRefGUI; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.util.DirectoryDialogConfiguration; import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.gui.util.ZipFileChooser; import org.jabref.logic.l10n.Localization; +import com.jfoenix.controls.JFXSnackbar; +import com.jfoenix.controls.JFXSnackbar.SnackbarEvent; +import com.jfoenix.controls.JFXSnackbarLayout; import org.controlsfx.dialog.ExceptionDialog; import org.controlsfx.dialog.ProgressDialog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class provides methods to create default @@ -51,18 +57,15 @@ */ public class FXDialogService implements DialogService { - private final Window mainWindow; + private static final Duration TOAST_MESSAGE_DISPLAY_TIME = Duration.millis(3000); + private static final Logger LOGGER = LoggerFactory.getLogger(FXDialogService.class); - /** - * @deprecated try not to initialize a new dialog service but reuse the one constructed in {@link org.jabref.gui.JabRefFrame}. - */ - @Deprecated - public FXDialogService() { - this(null); - } + private final Window mainWindow; + private final JFXSnackbar statusLine; - public FXDialogService(Window mainWindow) { + public FXDialogService(Window mainWindow, Pane mainPane) { this.mainWindow = mainWindow; + this.statusLine = new JFXSnackbar(mainPane); } private static FXDialog createDialog(AlertType type, String title, String content) { @@ -112,6 +115,7 @@ public Optional showChoiceDialogAndWait(String title, String content, Str ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.OK_DONE); choiceDialog.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, okButtonType); choiceDialog.setHeaderText(title); + choiceDialog.setTitle(title); choiceDialog.setContentText(content); return choiceDialog.showAndWait(); @@ -252,7 +256,8 @@ public void showProgressDialogAndWait(String title, String content, Task @Override public void notify(String message) { - JabRefGUI.getMainFrame().output(message); + LOGGER.info(message); + statusLine.fireEvent(new SnackbarEvent(new JFXSnackbarLayout(message), TOAST_MESSAGE_DISPLAY_TIME, null)); } @Override diff --git a/src/main/java/org/jabref/gui/GUIGlobals.java b/src/main/java/org/jabref/gui/GUIGlobals.java index e1f145054ff..12d55f69bbe 100644 --- a/src/main/java/org/jabref/gui/GUIGlobals.java +++ b/src/main/java/org/jabref/gui/GUIGlobals.java @@ -10,9 +10,6 @@ import org.jabref.logic.l10n.Localization; import org.jabref.preferences.JabRefPreferences; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Static variables for graphics files and keyboard shortcuts. */ @@ -32,11 +29,6 @@ public class GUIGlobals { public static final String UNTITLED_TITLE = Localization.lang("untitled"); - // Colors. - public static final Color ENTRY_EDITOR_LABEL_COLOR = new Color(100, 100, 150); // Empty field, blue. - - private static final Logger LOGGER = LoggerFactory.getLogger(GUIGlobals.class); - private GUIGlobals() { } diff --git a/src/main/java/org/jabref/gui/JEditorPaneWithHighlighting.java b/src/main/java/org/jabref/gui/JEditorPaneWithHighlighting.java deleted file mode 100644 index 71235c5d08e..00000000000 --- a/src/main/java/org/jabref/gui/JEditorPaneWithHighlighting.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.jabref.gui; - -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.JEditorPane; -import javax.swing.text.BadLocationException; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Document; -import javax.swing.text.Highlighter; -import javax.swing.text.LayeredHighlighter.LayerPainter; - -import org.jabref.gui.fieldeditors.JTextAreaWithHighlighting; -import org.jabref.logic.search.SearchQueryHighlightListener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JEditorPaneWithHighlighting extends JEditorPane implements SearchQueryHighlightListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(JTextAreaWithHighlighting.class); - - public void highlightPattern(Optional highlightPattern) { - Highlighter highlighter = getHighlighter(); - highlighter.removeAllHighlights(); - - if ((highlightPattern == null) || !highlightPattern.isPresent()) { - return; - } - - String text = getDocumentText(); - - Matcher matcher = highlightPattern.get().matcher(text); - LayerPainter painter = DefaultHighlighter.DefaultPainter; - while (matcher.find()) { - try { - highlighter.addHighlight(matcher.start(), matcher.end(), painter); - } catch (BadLocationException ble) { - // should not occur if matcher works right - LOGGER.warn("Highlighting not possible, bad location", ble); - } - } - } - - private String getDocumentText() { - Document doc = getDocument(); - String text; - try { - text = doc.getText(0, doc.getLength()); - } catch (Exception e) { - LOGGER.error("Error while getting document text"); - text = ""; - } - return text; - } -} diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 80f7b821519..ef90ce04618 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -25,6 +25,7 @@ import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; +import javafx.geometry.Orientation; import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.Button; @@ -33,6 +34,7 @@ import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.ProgressBar; +import javafx.scene.control.Separator; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.SplitPane; import javafx.scene.control.Tab; @@ -48,30 +50,25 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; import javafx.stage.Stage; -import javafx.util.Duration; import org.jabref.Globals; import org.jabref.JabRefExecutorService; import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.Actions; -import org.jabref.gui.actions.AutoLinkFilesAction; import org.jabref.gui.actions.BibtexKeyPatternAction; import org.jabref.gui.actions.ConnectToSharedDatabaseCommand; import org.jabref.gui.actions.CopyFilesAction; -import org.jabref.gui.actions.CustomizeEntryAction; import org.jabref.gui.actions.CustomizeKeyBindingAction; -import org.jabref.gui.actions.DatabasePropertiesAction; import org.jabref.gui.actions.EditExternalFileTypesAction; import org.jabref.gui.actions.ErrorConsoleAction; +import org.jabref.gui.actions.LibraryPropertiesAction; import org.jabref.gui.actions.LookupIdentifierAction; +import org.jabref.gui.actions.ManageContentSelectorAction; import org.jabref.gui.actions.ManageCustomExportsAction; import org.jabref.gui.actions.ManageCustomImportsAction; import org.jabref.gui.actions.ManageJournalsAction; -import org.jabref.gui.actions.ManageKeywordsAction; -import org.jabref.gui.actions.ManageProtectedTermsAction; import org.jabref.gui.actions.NewDatabaseAction; import org.jabref.gui.actions.NewEntryAction; -import org.jabref.gui.actions.NewEntryFromPlainTextAction; import org.jabref.gui.actions.NewSubLibraryAction; import org.jabref.gui.actions.OldDatabaseCommandWrapper; import org.jabref.gui.actions.OpenBrowserAction; @@ -82,33 +79,38 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.actions.StandardActions; import org.jabref.gui.dialogs.AutosaveUIManager; +import org.jabref.gui.edit.ManageKeywordsAction; import org.jabref.gui.edit.MassSetFieldsAction; import org.jabref.gui.exporter.ExportCommand; import org.jabref.gui.exporter.ExportToClipboardAction; import org.jabref.gui.exporter.SaveAllAction; import org.jabref.gui.exporter.SaveDatabaseAction; +import org.jabref.gui.externalfiles.AutoLinkFilesAction; import org.jabref.gui.externalfiles.FindUnlinkedFilesAction; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.help.AboutAction; import org.jabref.gui.help.HelpAction; import org.jabref.gui.importer.ImportCommand; -import org.jabref.gui.importer.ImportInspectionDialog; +import org.jabref.gui.importer.ImportEntriesDialog; import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.integrity.IntegrityCheckAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.menus.FileHistoryMenu; import org.jabref.gui.mergeentries.MergeEntriesAction; -import org.jabref.gui.push.PushToApplicationButton; +import org.jabref.gui.metadata.BibtexStringEditorAction; +import org.jabref.gui.metadata.PreambleEditor; +import org.jabref.gui.protectedterms.ManageProtectedTermsAction; +import org.jabref.gui.push.PushToApplicationAction; import org.jabref.gui.push.PushToApplications; import org.jabref.gui.search.GlobalSearchBar; import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; import org.jabref.gui.undo.CountingUndoManager; +import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.autosaveandbackup.AutosaveManager; import org.jabref.logic.autosaveandbackup.BackupManager; import org.jabref.logic.importer.IdFetcher; import org.jabref.logic.importer.OpenDatabase; -import org.jabref.logic.importer.OutputPrinter; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.importer.WebFetchers; import org.jabref.logic.l10n.Localization; @@ -116,19 +118,16 @@ import org.jabref.logic.undo.AddUndoableActionEvent; import org.jabref.logic.undo.UndoChangeEvent; import org.jabref.logic.undo.UndoRedoEvent; -import org.jabref.logic.util.OS; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; 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.BibtexEntryTypes; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.LastFocusedTabPreferences; -import org.jabref.preferences.SearchPreferences; import com.google.common.eventbus.Subscribe; import com.jfoenix.controls.JFXSnackbar; @@ -137,23 +136,21 @@ import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import osx.macadapter.MacAdapter; /** * The main window of the application. */ -public class JabRefFrame extends BorderPane implements OutputPrinter { +public class JabRefFrame extends BorderPane { // Frame titles. public static final String FRAME_TITLE = "JabRef"; private static final Logger LOGGER = LoggerFactory.getLogger(JabRefFrame.class); - private static final Duration TOAST_MESSAGE_DISPLAY_TIME = Duration.millis(3000); private final SplitPane splitPane = new SplitPane(); private final JabRefPreferences prefs = Globals.prefs; private final GlobalSearchBar globalSearchBar = new GlobalSearchBar(this); - private final JFXSnackbar statusLine = new JFXSnackbar(this); + private final ProgressBar progressBar = new ProgressBar(); private final FileHistoryMenu fileHistory = new FileHistoryMenu(prefs, this); @@ -174,14 +171,12 @@ public class JabRefFrame extends BorderPane implements OutputPrinter { private SidePaneManager sidePaneManager; private TabPane tabbedPane; private PushToApplications pushApplications; - private final CountingUndoManager undoManager = new CountingUndoManager(); private final DialogService dialogService; private SidePane sidePane; public JabRefFrame(Stage mainStage) { this.mainStage = mainStage; - this.dialogService = new FXDialogService(mainStage); - init(); + this.dialogService = new FXDialogService(mainStage, this); } /** @@ -207,7 +202,7 @@ private static void setEnabled(List list, boolean enabled) { } } - private void init() { + public void init() { sidePaneManager = new SidePaneManager(Globals.prefs, this); sidePane = sidePaneManager.getPane(); @@ -267,16 +262,14 @@ private void init() { // Poor-mans binding to global state // We need to invoke this in the JavaFX thread as all the listeners sit there Platform.runLater(() -> Globals.stateManager.activeDatabaseProperty().setValue(Optional.of(currentBasePanel.getBibDatabaseContext()))); - if (new SearchPreferences(Globals.prefs).isGlobalSearch()) { - globalSearchBar.performSearch(); - } else { - String content = ""; - Optional currentSearchQuery = currentBasePanel.getCurrentSearchQuery(); - if (currentSearchQuery.isPresent()) { - content = currentSearchQuery.get().getQuery(); - } - globalSearchBar.setSearchTerm(content); + + // Update search query + String content = ""; + Optional currentSearchQuery = currentBasePanel.getCurrentSearchQuery(); + if (currentSearchQuery.isPresent()) { + content = currentSearchQuery.get().getQuery(); } + globalSearchBar.setSearchTerm(content); currentBasePanel.getPreviewPanel().updateLayout(Globals.prefs.getPreviewPreferences()); @@ -292,18 +285,6 @@ private void init() { currentBasePanel.getUndoManager().postUndoRedoEvent(); currentBasePanel.getMainTable().requestFocus(); }); - - //Note: The registration of Apple event is at the end of initialization, because - //if the events happen too early (ie when the window is not initialized yet), the - //opened (double-clicked) documents are not displayed. - if (OS.OS_X) { - try { - new MacAdapter().registerMacEvents(this); - } catch (Exception e) { - LOGGER.error("Could not interface with Mac OS X methods.", e); - } - } - initShowTrackingNotification(); } @@ -497,17 +478,8 @@ public boolean quit() { context.getDatabaseFile().map(File::getAbsolutePath).ifPresent(filenames::add); } - // Wait for save operations to finish - for (int i = 0; i < tabbedPane.getTabs().size(); i++) { - if (getBasePanelAt(i).isSaving()) { - // There is a database still being saved, so we need to wait. - WaitForSaveOperation w = new WaitForSaveOperation(this); - w.show(); // This method won't return until canceled or the save operation is done. - if (w.canceled()) { - return false; // The user clicked cancel. - } - } - } + WaitForSaveFinishedDialog waitForSaveFinishedDialog = new WaitForSaveFinishedDialog(dialogService); + waitForSaveFinishedDialog.showAndWait(getBasePanelList()); // Good bye! tearDownJabRef(filenames); @@ -554,32 +526,6 @@ public void changed(ObservableValue observable, Boolean oldVa }); setCenter(splitPane); - - /* - GridBagLayout gbl = new GridBagLayout(); - GridBagConstraints con = new GridBagConstraints(); - con.fill = GridBagConstraints.BOTH; - con.anchor = GridBagConstraints.WEST; - JPanel status = new JPanel(); - status.setLayout(gbl); - con.weighty = 0; - con.weightx = 0; - con.gridwidth = 1; - con.insets = new Insets(0, 2, 0, 0); - gbl.setConstraints(statusLabel, con); - status.add(statusLabel); - con.weightx = 1; - con.insets = new Insets(0, 4, 0, 0); - con.gridwidth = 1; - gbl.setConstraints(statusLine, con); - status.add(statusLine); - con.weightx = 0; - con.gridwidth = GridBagConstraints.REMAINDER; - con.insets = new Insets(2, 4, 2, 2); - gbl.setConstraints(progressBar, con); - status.add(progressBar); - statusLabel.setForeground(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR.darker()); - */ } private void setDividerPosition() { @@ -615,20 +561,21 @@ private Node createToolbar() { leftSide.prefWidthProperty().bind(sidePane.widthProperty()); leftSide.maxWidthProperty().bind(sidePane.widthProperty()); - PushToApplicationButton pushToExternal = new PushToApplicationButton(this, pushApplications.getApplications()); + PushToApplicationAction pushToApplicationAction = new PushToApplicationAction(this, Globals.stateManager); HBox rightSide = new HBox( factory.createIconButton(StandardActions.NEW_ARTICLE, new NewEntryAction(this, BiblatexEntryTypes.ARTICLE, dialogService, Globals.prefs)), factory.createIconButton(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, Globals.stateManager)), - + new Separator(Orientation.VERTICAL), factory.createIconButton(StandardActions.UNDO, new OldDatabaseCommandWrapper(Actions.UNDO, this, Globals.stateManager)), factory.createIconButton(StandardActions.REDO, new OldDatabaseCommandWrapper(Actions.REDO, this, Globals.stateManager)), factory.createIconButton(StandardActions.CUT, new OldDatabaseCommandWrapper(Actions.CUT, this, Globals.stateManager)), factory.createIconButton(StandardActions.COPY, new OldDatabaseCommandWrapper(Actions.COPY, this, Globals.stateManager)), factory.createIconButton(StandardActions.PASTE, new OldDatabaseCommandWrapper(Actions.PASTE, this, Globals.stateManager)), - + new Separator(Orientation.VERTICAL), + factory.createIconButton(pushToApplicationAction.getActionInformation(), pushToApplicationAction), + factory.createIconButton(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, Globals.stateManager)), factory.createIconButton(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, Globals.stateManager)), - factory.createIconButton(pushToExternal.getMenuAction(), pushToExternal), - + new Separator(Orientation.VERTICAL), factory.createIconButton(StandardActions.FORK_ME, new OpenBrowserAction("https://github.com/JabRef/jabref")), factory.createIconButton(StandardActions.OPEN_FACEBOOK, new OpenBrowserAction("https://www.facebook.com/JabRef/")), factory.createIconButton(StandardActions.OPEN_TWITTER, new OpenBrowserAction("https://twitter.com/jabref_org")) @@ -730,35 +677,35 @@ private MenuBar createMenu() { Menu help = new Menu(Localization.lang("Help")); file.getItems().addAll( - factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBTEX, new NewDatabaseAction(this, BibDatabaseMode.BIBTEX)), - factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBLATEX, new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX)), + factory.createSubMenu(StandardActions.NEW_LIBRARY, + factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBTEX, new NewDatabaseAction(this, BibDatabaseMode.BIBTEX)), + factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBLATEX, new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX))), + factory.createMenuItem(StandardActions.OPEN_LIBRARY, getOpenDatabaseAction()), + fileHistory, factory.createMenuItem(StandardActions.SAVE_LIBRARY, new OldDatabaseCommandWrapper(Actions.SAVE, this, Globals.stateManager)), factory.createMenuItem(StandardActions.SAVE_LIBRARY_AS, new OldDatabaseCommandWrapper(Actions.SAVE_AS, this, Globals.stateManager)), factory.createMenuItem(StandardActions.SAVE_ALL, new SaveAllAction(this)), - factory.createSubMenu(StandardActions.IMPORT_EXPORT, + new SeparatorMenuItem(), + + factory.createSubMenu(StandardActions.IMPORT, factory.createMenuItem(StandardActions.MERGE_DATABASE, new OldDatabaseCommandWrapper(Actions.MERGE_DATABASE, this, Globals.stateManager)), // TODO: merge with import factory.createMenuItem(StandardActions.IMPORT_INTO_CURRENT_LIBRARY, new ImportCommand(this, false)), - factory.createMenuItem(StandardActions.IMPORT_INTO_NEW_LIBRARY, new ImportCommand(this, true)), + factory.createMenuItem(StandardActions.IMPORT_INTO_NEW_LIBRARY, new ImportCommand(this, true))), + + factory.createSubMenu(StandardActions.EXPORT, factory.createMenuItem(StandardActions.EXPORT_ALL, new ExportCommand(this, false, Globals.prefs)), factory.createMenuItem(StandardActions.EXPORT_SELECTED, new ExportCommand(this, true, Globals.prefs)), factory.createMenuItem(StandardActions.SAVE_SELECTED_AS_PLAIN_BIBTEX, new OldDatabaseCommandWrapper(Actions.SAVE_SELECTED_AS_PLAIN, this, Globals.stateManager))), - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.CONNECT_TO_SHARED_DB, new ConnectToSharedDatabaseCommand(this)), factory.createMenuItem(StandardActions.PULL_CHANGES_FROM_SHARED_DB, new OldDatabaseCommandWrapper(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, this, Globals.stateManager)), new SeparatorMenuItem(), - fileHistory, - - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.CLOSE_LIBRARY, new CloseDatabaseAction()), factory.createMenuItem(StandardActions.QUIT, new CloseAction()) - ); edit.getItems().addAll( @@ -783,16 +730,13 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, Globals.stateManager)), - - new SeparatorMenuItem() - + factory.createMenuItem(StandardActions.MANAGE_KEYWORDS, new ManageKeywordsAction(this)) ); if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { boolean menuItemAdded = false; if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { - edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.RANKING, factory, undoManager)); + edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.RANKING, factory, Globals.undoManager)); menuItemAdded = true; } @@ -812,12 +756,12 @@ private MenuBar createMenu() { } if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { - edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.PRIORITY, factory, undoManager)); + edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.PRIORITY, factory, Globals.undoManager)); menuItemAdded = true; } if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { - edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.READ_STATUS, factory, undoManager)); + edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.READ_STATUS, factory, Globals.undoManager)); menuItemAdded = true; } @@ -825,28 +769,18 @@ private MenuBar createMenu() { edit.getItems().add(new SeparatorMenuItem()); } } - - edit.getItems().addAll( - factory.createMenuItem(StandardActions.MANAGE_KEYWORDS, new ManageKeywordsAction(this)), - factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.MASS_SET_FIELDS, new MassSetFieldsAction(this)) - - ); - + //@formatter:off library.getItems().addAll( - factory.createMenuItem(StandardActions.NEW_ARTICLE, new NewEntryAction(this, BibtexEntryTypes.ARTICLE, dialogService, Globals.prefs)), factory.createMenuItem(StandardActions.NEW_ENTRY, new NewEntryAction(this, dialogService, Globals.prefs)), - factory.createMenuItem(StandardActions.NEW_ENTRY_FROM_PLAINTEX, new NewEntryFromPlainTextAction(this, Globals.prefs.getUpdateFieldPreferences(), dialogService, Globals.prefs)), - - new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, Globals.stateManager)), new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.LIBRARY_PROPERTIES, new DatabasePropertiesAction(this)), + factory.createMenuItem(StandardActions.LIBRARY_PROPERTIES, new LibraryPropertiesAction(this, dialogService)), factory.createMenuItem(StandardActions.EDIT_PREAMBLE, new PreambleEditor(this)), - factory.createMenuItem(StandardActions.EDIT_STRINGS, new OldDatabaseCommandWrapper(Actions.EDIT_STRINGS, this, Globals.stateManager)) + factory.createMenuItem(StandardActions.EDIT_STRINGS, new BibtexStringEditorAction(this)), + factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new BibtexKeyPatternAction(this)), + factory.createMenuItem(StandardActions.MASS_SET_FIELDS, new MassSetFieldsAction(this)) ); Menu lookupIdentifiers = factory.createSubMenu(StandardActions.LOOKUP_DOC_IDENTIFIER); @@ -858,70 +792,68 @@ private MenuBar createMenu() { quality.getItems().addAll( factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this, dialogService)), factory.createMenuItem(StandardActions.MERGE_ENTRIES, new MergeEntriesAction(this)), - - new SeparatorMenuItem(), - - factory.createMenuItem(StandardActions.RESOLVE_DUPLICATE_KEYS, new OldDatabaseCommandWrapper(Actions.RESOLVE_DUPLICATE_KEYS, this, Globals.stateManager)), factory.createMenuItem(StandardActions.CHECK_INTEGRITY, new IntegrityCheckAction(this)), factory.createMenuItem(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, Globals.stateManager)), new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction()), - factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this)), - lookupIdentifiers, - factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new OldDatabaseCommandWrapper(Actions.DOWNLOAD_FULL_TEXT, this, Globals.stateManager)) + factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction(this, prefs)) ); - SidePaneComponent webSearch = sidePaneManager.getComponent(SidePaneType.WEB_SEARCH); - SidePaneComponent groups = sidePaneManager.getComponent(SidePaneType.GROUPS); - SidePaneComponent openOffice = sidePaneManager.getComponent(SidePaneType.OPEN_OFFICE); - - view.getItems().addAll( - factory.createMenuItem(webSearch.getToggleAction(), webSearch.getToggleCommand()), - factory.createMenuItem(groups.getToggleAction(), groups.getToggleCommand()), - factory.createMenuItem(StandardActions.TOGGLE_PREVIEW, new OldDatabaseCommandWrapper(Actions.TOGGLE_PREVIEW, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.EDIT_ENTRY, new OldDatabaseCommandWrapper(Actions.EDIT, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.SHOW_PDV_VIEWER, new ShowDocumentViewerAction()), - - new SeparatorMenuItem(), - - factory.createMenuItem(StandardActions.SELECT_ALL, new OldDatabaseCommandWrapper(Actions.SELECT_ALL, this, Globals.stateManager)), - - new SeparatorMenuItem(), - - factory.createMenuItem(StandardActions.NEXT_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.NEXT_PREVIEW_STYLE, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.PREVIOUS_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.PREVIOUS_PREVIEW_STYLE, this, Globals.stateManager)) - ); - - PushToApplicationButton pushToExternal = new PushToApplicationButton(this, pushApplications.getApplications()); + final PushToApplicationAction pushToApplicationAction = new PushToApplicationAction(this, Globals.stateManager); tools.getItems().addAll( factory.createMenuItem(StandardActions.NEW_SUB_LIBRARY_FROM_AUX, new NewSubLibraryAction(this)), + factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this)), factory.createMenuItem(StandardActions.WRITE_XMP, new OldDatabaseCommandWrapper(Actions.WRITE_XMP, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_LINKED_FILES, new CopyFilesAction(this)), new SeparatorMenuItem(), - factory.createMenuItem(openOffice.getToggleAction(), openOffice.getToggleCommand()), - factory.createMenuItem(pushToExternal.getMenuAction(), pushToExternal), + lookupIdentifiers, + factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new OldDatabaseCommandWrapper(Actions.DOWNLOAD_FULL_TEXT, this, Globals.stateManager)), new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.OPEN_FOLDER, new OldDatabaseCommandWrapper(Actions.OPEN_FOLDER, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.OPEN_FILE, new OldDatabaseCommandWrapper(Actions.OPEN_EXTERNAL_FILE, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.OPEN_URL, new OldDatabaseCommandWrapper(Actions.OPEN_URL, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OldDatabaseCommandWrapper(Actions.OPEN_CONSOLE, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.COPY_LINKED_FILES, new CopyFilesAction(this)), + factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, Globals.stateManager)), + factory.createMenuItem(pushToApplicationAction.getActionInformation(), pushToApplicationAction), - new SeparatorMenuItem(), + factory.createSubMenu(StandardActions.ABBREVIATE, + factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_MEDLINE, this, Globals.stateManager))), - factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_MEDLINE, this, Globals.stateManager)), factory.createMenuItem(StandardActions.UNABBREVIATE, new OldDatabaseCommandWrapper(Actions.UNABBREVIATE, this, Globals.stateManager)) ); + SidePaneComponent webSearch = sidePaneManager.getComponent(SidePaneType.WEB_SEARCH); + SidePaneComponent groups = sidePaneManager.getComponent(SidePaneType.GROUPS); + SidePaneComponent openOffice = sidePaneManager.getComponent(SidePaneType.OPEN_OFFICE); + + view.getItems().add(new SeparatorMenuItem()); + view.setOnShowing(event -> { + view.getItems().clear(); + view.getItems().addAll( + factory.createCheckMenuItem(webSearch.getToggleAction(), webSearch.getToggleCommand(), sidePaneManager.isComponentVisible(SidePaneType.WEB_SEARCH)), + factory.createCheckMenuItem(groups.getToggleAction(), groups.getToggleCommand(), sidePaneManager.isComponentVisible(SidePaneType.GROUPS)), + factory.createCheckMenuItem(openOffice.getToggleAction(), openOffice.getToggleCommand(), sidePaneManager.isComponentVisible(SidePaneType.OPEN_OFFICE)), + + new SeparatorMenuItem(), + + factory.createCheckMenuItem(StandardActions.TOGGLE_PREVIEW, new OldDatabaseCommandWrapper(Actions.TOGGLE_PREVIEW, this, Globals.stateManager), Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()), + factory.createMenuItem(StandardActions.NEXT_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.NEXT_PREVIEW_STYLE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.PREVIOUS_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.PREVIOUS_PREVIEW_STYLE, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction()), + factory.createMenuItem(StandardActions.EDIT_ENTRY, new OldDatabaseCommandWrapper(Actions.EDIT, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OldDatabaseCommandWrapper(Actions.OPEN_CONSOLE, this, Globals.stateManager)) + ); + }); + options.getItems().addAll( - factory.createMenuItem(StandardActions.SHOW_PREFS, new ShowPreferencesAction(this)), + factory.createMenuItem(StandardActions.SHOW_PREFS, new ShowPreferencesAction(this, Globals.TASK_EXECUTOR)), new SeparatorMenuItem(), @@ -931,13 +863,13 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.MANAGE_EXTERNAL_FILETYPES, new EditExternalFileTypesAction()), factory.createMenuItem(StandardActions.MANAGE_JOURNALS, new ManageJournalsAction()), factory.createMenuItem(StandardActions.CUSTOMIZE_KEYBINDING, new CustomizeKeyBindingAction()), - factory.createMenuItem(StandardActions.MANAGE_PROTECTED_TERMS, new ManageProtectedTermsAction(this, Globals.protectedTermsLoader)), + factory.createMenuItem(StandardActions.MANAGE_PROTECTED_TERMS, new ManageProtectedTermsAction()), new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.MANAGE_CONTENT_SELECTORS, new OldDatabaseCommandWrapper(Actions.MANAGE_SELECTORS, this, Globals.stateManager)), - factory.createMenuItem(StandardActions.CUSTOMIZE_ENTRY_TYPES, new CustomizeEntryAction(this)), - factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new BibtexKeyPatternAction(this)) + factory.createMenuItem(StandardActions.MANAGE_CONTENT_SELECTORS, new ManageContentSelectorAction(this)) + // TODO: Reenable customize entry types feature (https://github.com/JabRef/jabref/issues/4719) + //factory.createMenuItem(StandardActions.CUSTOMIZE_ENTRY_TYPES, new CustomizeEntryAction(this)), ); help.getItems().addAll( @@ -971,6 +903,7 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.ABOUT, new AboutAction()) ); + //@formatter:on MenuBar menu = new MenuBar(); menu.getStyleClass().add("mainMenu"); menu.getMenus().addAll( @@ -1011,16 +944,6 @@ public void addParserResult(ParserResult pr, boolean focusPanel) { } } - /** - * Displays the given message at the bottom of the main frame - * - * @deprecated use {@link DialogService#notify(String)} instead. However, do not remove this method, it's called from the dialogService - */ - @Deprecated - public void output(final String message) { - DefaultTaskExecutor.runInJavaFXThread(() -> statusLine.fireEvent(new SnackbarEvent(new JFXSnackbarLayout(message), TOAST_MESSAGE_DISPLAY_TIME, null))); - } - private void initActions() { /* openDatabaseOnlyActions.clear(); @@ -1172,6 +1095,10 @@ public void addTab(BasePanel basePanel, boolean raisePanel) { // add tab Tab newTab = new Tab(basePanel.getTabTitle(), basePanel); tabbedPane.getTabs().add(newTab); + newTab.setOnCloseRequest(event -> { + closeTab((BasePanel) newTab.getContent()); + event.consume(); + }); // update all tab titles updateAllTabTitles(); @@ -1221,21 +1148,16 @@ private boolean readyForAutosave(BibDatabaseContext context) { } /** - * This method does the job of adding imported entries into the active database, or into a new one. It shows the - * ImportInspectionDialog if preferences indicate it should be used. Otherwise it imports directly. + * Opens the import inspection dialog to let the user decide which of the given entries to import. * * @param panel The BasePanel to add to. * @param entries The entries to add. */ private void addImportedEntries(final BasePanel panel, final List entries) { - SwingUtilities.invokeLater(() -> { - ImportInspectionDialog diag = new ImportInspectionDialog(JabRefFrame.this, panel, - Localization.lang("Import"), false); - diag.addEntries(entries); - diag.entryListComplete(); - diag.setVisible(true); - diag.toFront(); - }); + BackgroundTask> task = BackgroundTask.wrap(() -> entries); + ImportEntriesDialog dialog = new ImportEntriesDialog(panel.getBibDatabaseContext(), task); + dialog.setTitle(Localization.lang("Import")); + dialog.showAndWait(); } public FileHistoryMenu getFileHistory() { @@ -1296,17 +1218,6 @@ private boolean isExistURLorDOI(List selectEntryList) { return false; } - @Override - public void showMessage(String message, String title, int msgType) { - JOptionPane.showMessageDialog(null, message, title, msgType); - } - - @Override - public void setStatus(String s) { - output(s); - } - - @Override public void showMessage(String message) { JOptionPane.showMessageDialog(null, message); } @@ -1336,18 +1247,20 @@ private boolean confirmClose(BasePanel panel) { // The user wants to save. try { SaveDatabaseAction saveAction = new SaveDatabaseAction(panel, Globals.prefs); - if (!saveAction.save()) { - // The action was either canceled or unsuccessful. - output(Localization.lang("Unable to save library")); - return false; + if (saveAction.save()) { + // Saved, now exit. + return true; } + // The action was either canceled or unsuccessful. + dialogService.notify(Localization.lang("Unable to save library")); } catch (Throwable ex) { - return false; + LOGGER.error("A problem occurred when trying to save the file", ex); + dialogService.showErrorDialogAndWait(Localization.lang("Save library"), Localization.lang("Could not save file."), ex); } - } else { - return !response.isPresent() || !response.get().equals(cancel); + // Save was cancelled or an error occurred. + return false; } - return false; + return !response.isPresent() || !response.get().equals(cancel); } private void closeTab(BasePanel panel) { @@ -1361,6 +1274,8 @@ private void closeTab(BasePanel panel) { if (panel.isModified() && (context.getLocation() == DatabaseLocation.LOCAL)) { if (confirmClose(panel)) { removeTab(panel); + } else { + return; } } else if (context.getLocation() == DatabaseLocation.SHARED) { context.convertToLocalDatabase(); @@ -1379,7 +1294,7 @@ private void removeTab(BasePanel panel) { panel.cleanUp(); tabbedPane.getTabs().remove(getTab(panel)); setWindowTitle(); - output(Localization.lang("Closed library") + '.'); + dialogService.notify(Localization.lang("Closed library") + '.'); // update tab titles updateAllTabTitles(); }); @@ -1406,7 +1321,7 @@ public GlobalSearchBar getGlobalSearchBar() { } public CountingUndoManager getUndoManager() { - return undoManager; + return Globals.undoManager; } public DialogService getDialogService() { @@ -1481,7 +1396,7 @@ private void setDefaultTableFontSize() { for (BasePanel basePanel : getBasePanelList()) { basePanel.updateTableFont(); } - setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); + dialogService.notify(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); } private void increaseTableFontSize() { @@ -1489,7 +1404,7 @@ private void increaseTableFontSize() { for (BasePanel basePanel : getBasePanelList()) { basePanel.updateTableFont(); } - setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); + dialogService.notify(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); } private void decreaseTableFontSize() { @@ -1501,7 +1416,7 @@ private void decreaseTableFontSize() { for (BasePanel basePanel : getBasePanelList()) { basePanel.updateTableFont(); } - setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); + dialogService.notify(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); } private class CloseDatabaseAction extends SimpleCommand { diff --git a/src/main/java/org/jabref/gui/OSXCompatibleToolbar.java b/src/main/java/org/jabref/gui/OSXCompatibleToolbar.java deleted file mode 100644 index f71c9e72af5..00000000000 --- a/src/main/java/org/jabref/gui/OSXCompatibleToolbar.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.jabref.gui; - -import java.awt.Component; - -import javax.swing.JButton; -import javax.swing.JToolBar; - -import org.jabref.logic.util.OS; - -public class OSXCompatibleToolbar extends JToolBar { - - public OSXCompatibleToolbar() { - } - - public OSXCompatibleToolbar(int orientation) { - super(orientation); - } - - public OSXCompatibleToolbar(String name) { - super(name); - } - - public OSXCompatibleToolbar(String name, int orientation) { - super(name, orientation); - } - - @Override - public Component add(Component a) { - if (a instanceof JButton) { - JButton button = (JButton) a; - if (OS.OS_X) { - button.putClientProperty("JButton.buttonType", "toolbar"); - } - } - - return super.add(a); - } - -} diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index bffcb4e2bd3..ff26ee6765b 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -24,7 +24,7 @@ import javafx.scene.web.WebView; import org.jabref.Globals; -import org.jabref.gui.externalfiles.NewDroppedFileHandler; +import org.jabref.gui.externalfiles.ExternalFilesEntryLinker; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; @@ -61,8 +61,9 @@ public class PreviewPanel extends ScrollPane implements SearchQueryHighlightList private final DialogService dialogService; private final KeyBindingRepository keyBindingRepository; - private String previewStyle; private final String defaultPreviewStyle = "Preview"; + private String previewStyle; + private CitationStyle citationStyle; private Optional basePanel = Optional.empty(); private boolean fixedLayout; @@ -79,11 +80,11 @@ public class PreviewPanel extends ScrollPane implements SearchQueryHighlightList private final WebView previewView; private Optional> citationStyleFuture = Optional.empty(); - private final NewDroppedFileHandler fileHandler; + private final ExternalFilesEntryLinker fileLinker; /** * @param panel (may be null) Only set this if the preview is associated to the main window. - * @param databaseContext Used for resolving pdf directories for links. Must not be null. + * @param databaseContext Used for resolving pdf directories for links. Must not be null, just pass a new empty BibDatabaseContext() */ public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext, KeyBindingRepository keyBindingRepository, PreviewPreferences preferences, DialogService dialogService, ExternalFileTypes externalFileTypes) { this.databaseContext = Objects.requireNonNull(databaseContext); @@ -92,11 +93,7 @@ public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext, KeyBind this.clipBoardManager = Globals.clipboardManager; this.keyBindingRepository = keyBindingRepository; - fileHandler = new NewDroppedFileHandler(dialogService, databaseContext, externalFileTypes, - Globals.prefs.getFilePreferences(), - Globals.prefs.getImportFormatPreferences(), - Globals.prefs.getUpdateFieldPreferences(), - Globals.getFileUpdateMonitor()); + fileLinker = new ExternalFilesEntryLinker(externalFileTypes, Globals.prefs.getFilePreferences(), databaseContext); // Set up scroll pane for preview pane setFitToHeight(true); @@ -134,19 +131,18 @@ public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext, KeyBind List files = event.getDragboard().getFiles().stream().map(File::toPath).collect(Collectors.toList()); if (event.getTransferMode() == TransferMode.MOVE) { - LOGGER.debug("Mode MOVE"); //shift on win or no modifier - fileHandler.addToEntryRenameAndMoveToFileDir(entry, files); + fileLinker.moveFilesToFileDirAndAddToEntry(entry, files); } if (event.getTransferMode() == TransferMode.LINK) { LOGGER.debug("Node LINK"); //alt on win - fileHandler.addToEntry(entry, files); - + fileLinker.addFilesToEntry(entry, files); } if (event.getTransferMode() == TransferMode.COPY) { LOGGER.debug("Mode Copy"); //ctrl on win, no modifier on Xubuntu - fileHandler.copyFilesToFileDirAndAddToEntry(entry, files); + fileLinker.copyFilesToFileDirAndAddToEntry(entry, files); } + success = true; } event.setDropCompleted(success); @@ -224,24 +220,25 @@ private void updateLayout(PreviewPreferences previewPreferences, boolean init) { String style = previewPreferences.getCurrentPreviewStyle(); if (previewStyle == null) { previewStyle = style; + CitationStyle.createCitationStyleFromFile(style).ifPresent(cs -> citationStyle = cs); } if (basePanel.isPresent() && !previewStyle.equals(style)) { if (CitationStyle.isCitationStyleFile(style)) { layout = Optional.empty(); CitationStyle.createCitationStyleFromFile(style) - .ifPresent(citationStyle -> { - basePanel.get().getCitationStyleCache().setCitationStyle(citationStyle); - if (!init) { - basePanel.get().output(Localization.lang("Preview style changed to: %0", citationStyle.getTitle())); - } - }); + .ifPresent(cs -> { + citationStyle = cs; + if (!init) { + basePanel.get().output(Localization.lang("Preview style changed to: %0", citationStyle.getTitle())); + } + }); previewStyle = style; - } else { - previewStyle = defaultPreviewStyle; - updatePreviewLayout(previewPreferences.getPreviewStyle(), previewPreferences.getLayoutFormatterPreferences()); - if (!init) { - basePanel.get().output(Localization.lang("Preview style changed to: %0", Localization.lang("Preview"))); - } + } + } else { + previewStyle = defaultPreviewStyle; + updatePreviewLayout(previewPreferences.getPreviewStyle(), previewPreferences.getLayoutFormatterPreferences()); + if (!init) { + basePanel.get().output(Localization.lang("Preview style changed to: %0", Localization.lang("Preview"))); } } @@ -299,6 +296,9 @@ public void update() { .doLayout(entry, databaseContext.getDatabase()))); setPreviewLabel(sb.toString()); } else if (basePanel.isPresent() && bibEntry.isPresent()) { + if ((citationStyle != null) && !previewStyle.equals(defaultPreviewStyle)) { + basePanel.get().getCitationStyleCache().setCitationStyle(citationStyle); + } Future citationStyleWorker = BackgroundTask .wrap(() -> basePanel.get().getCitationStyleCache().getCitationFor(bibEntry.get())) .onRunning(() -> { @@ -363,11 +363,13 @@ public void close() { private void copyPreviewToClipBoard() { StringBuilder previewStringContent = new StringBuilder(); Document document = previewView.getEngine().getDocument(); - NodeList nodeList = document.getElementsByTagName("*"); + NodeList nodeList = document.getElementsByTagName("html"); + + //Nodelist does not implement iterable for (int i = 0; i < nodeList.getLength(); i++) { Element element = (Element) nodeList.item(i); - previewStringContent.append(element.getNodeValue()).append("\n"); + previewStringContent.append(element.getTextContent()); } ClipboardContent content = new ClipboardContent(); diff --git a/src/main/java/org/jabref/gui/SaveOrderConfigDisplay.fxml b/src/main/java/org/jabref/gui/SaveOrderConfigDisplay.fxml new file mode 100644 index 00000000000..4bee6851ab0 --- /dev/null +++ b/src/main/java/org/jabref/gui/SaveOrderConfigDisplay.fxml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/SaveOrderConfigDisplay.java b/src/main/java/org/jabref/gui/SaveOrderConfigDisplay.java deleted file mode 100644 index 5103fba8d29..00000000000 --- a/src/main/java/org/jabref/gui/SaveOrderConfigDisplay.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.jabref.gui; - -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Objects; - -import javafx.collections.FXCollections; -import javafx.scene.Node; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.layout.GridPane; -import javafx.scene.text.Font; - -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.InternalBibtexFields; -import org.jabref.model.metadata.SaveOrderConfig; -import org.jabref.model.metadata.SaveOrderConfig.SortCriterion; - -public class SaveOrderConfigDisplay { - - private GridPane panel; - private ComboBox savePriSort; - private ComboBox saveSecSort; - private ComboBox saveTerSort; - private CheckBox savePriDesc; - private CheckBox saveSecDesc; - private CheckBox saveTerDesc; - - - public SaveOrderConfigDisplay() { - init(); - } - - private void init() { - List fieldNames = InternalBibtexFields.getAllPublicFieldNames(); - fieldNames.add(BibEntry.KEY_FIELD); - Collections.sort(fieldNames); - savePriSort = new ComboBox<>(FXCollections.observableArrayList(fieldNames)); - savePriSort.setEditable(true); - saveSecSort = new ComboBox<>(FXCollections.observableArrayList(fieldNames)); - saveSecSort.setEditable(true); - saveTerSort = new ComboBox<>(FXCollections.observableArrayList(fieldNames)); - saveTerSort.setEditable(true); - - savePriDesc = new CheckBox(Localization.lang("Descending")); - saveSecDesc = new CheckBox(Localization.lang("Descending")); - saveTerDesc = new CheckBox(Localization.lang("Descending")); - - Font font = new Font(10); - GridPane builder = new GridPane(); - Label primarySortCriterion = new Label(Localization.lang("Primary sort criterion")); - primarySortCriterion.setFont(font); - builder.add(primarySortCriterion, 1, 1); - builder.add(savePriSort, 2, 1); - builder.add(savePriDesc, 3, 1); - - Label secondarySortCriterion = new Label(Localization.lang("Secondary sort criterion")); - secondarySortCriterion.setFont(font); - builder.add(secondarySortCriterion, 1, 2); - builder.add(saveSecSort, 2, 2); - builder.add(saveSecDesc, 3, 2); - - Label tertiarySortCriterion = new Label(Localization.lang("Tertiary sort criterion")); - tertiarySortCriterion.setFont(font); - builder.add(tertiarySortCriterion, 1, 3); - builder.add(saveTerSort, 2, 3); - builder.add(saveTerDesc, 3, 3); - panel = builder; - } - - public Node getJFXPanel() { - return panel; - } - - public void setEnabled(boolean enabled) { - savePriSort.setDisable(!enabled); - savePriDesc.setDisable(!enabled); - saveSecSort.setDisable(!enabled); - saveSecDesc.setDisable(!enabled); - saveTerSort.setDisable(!enabled); - saveTerDesc.setDisable(!enabled); - } - - public SaveOrderConfig getSaveOrderConfig() { - SaveOrderConfig saveOrderConfig = new SaveOrderConfig(); - SortCriterion primary = new SortCriterion(getSelectedItemAsLowerCaseTrim(savePriSort), savePriDesc.isSelected()); - saveOrderConfig.getSortCriteria().add(primary); - SortCriterion secondary = new SortCriterion(getSelectedItemAsLowerCaseTrim(saveSecSort), saveSecDesc.isSelected()); - saveOrderConfig.getSortCriteria().add(secondary); - SortCriterion tertiary = new SortCriterion(getSelectedItemAsLowerCaseTrim(saveTerSort), saveTerDesc.isSelected()); - saveOrderConfig.getSortCriteria().add(tertiary); - - return saveOrderConfig; - } - - public void setSaveOrderConfig(SaveOrderConfig saveOrderConfig) { - Objects.requireNonNull(saveOrderConfig); - - savePriSort.setValue(saveOrderConfig.getSortCriteria().get(0).field); - savePriDesc.setSelected(saveOrderConfig.getSortCriteria().get(0).descending); - saveSecSort.setValue(saveOrderConfig.getSortCriteria().get(1).field); - saveSecDesc.setSelected(saveOrderConfig.getSortCriteria().get(1).descending); - saveTerSort.setValue(saveOrderConfig.getSortCriteria().get(2).field); - saveTerDesc.setSelected(saveOrderConfig.getSortCriteria().get(2).descending); - } - - private String getSelectedItemAsLowerCaseTrim(ComboBox sortBox) { - return sortBox.getValue().toLowerCase(Locale.ROOT).trim(); - } -} diff --git a/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java new file mode 100644 index 00000000000..aeca6f4ddad --- /dev/null +++ b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayView.java @@ -0,0 +1,81 @@ +package org.jabref.gui; + +import javax.inject.Inject; + +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.RadioButton; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.GridPane; + +import org.jabref.logic.l10n.Localization; +import org.jabref.model.metadata.SaveOrderConfig; +import org.jabref.preferences.PreferencesService; + +import com.airhacks.afterburner.views.ViewLoader; + +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 RadioButton exportInSpecifiedOrder; + @FXML private RadioButton exportInTableOrder; + @FXML private RadioButton exportInOriginalOrder; + @FXML private CheckBox savePriDesc; + @FXML private CheckBox saveSecDesc; + @FXML private CheckBox saveTerDesc; + @Inject private PreferencesService preferencesService; + + private SaveOrderConfigDisplayViewModel viewModel; + + public SaveOrderConfigDisplayView(SaveOrderConfig config) { + this.config = config; + + ViewLoader.view(this) + .root(this) + .load(); + } + + @FXML + private void initialize() { + + viewModel = new SaveOrderConfigDisplayViewModel(config, preferencesService); + + exportInSpecifiedOrder.selectedProperty().bindBidirectional(viewModel.saveInSpecifiedOrderProperty()); + exportInTableOrder.selectedProperty().bindBidirectional(viewModel.saveInTableOrderProperty()); + exportInOriginalOrder.selectedProperty().bindBidirectional(viewModel.saveInOriginalProperty()); + + savePriSort.itemsProperty().bindBidirectional(viewModel.priSortFieldsProperty()); + saveSecSort.itemsProperty().bindBidirectional(viewModel.secSortFieldsProperty()); + saveTerSort.itemsProperty().bindBidirectional(viewModel.terSortFieldsProperty()); + + savePriSort.valueProperty().bindBidirectional(viewModel.savePriSortSelectedValueProperty()); + saveSecSort.valueProperty().bindBidirectional(viewModel.saveSecSortSelectedValueProperty()); + saveTerSort.valueProperty().bindBidirectional(viewModel.saveTerSortSelectedValueProperty()); + + savePriDesc.selectedProperty().bindBidirectional(viewModel.savePriDescPropertySelected()); + saveSecDesc.selectedProperty().bindBidirectional(viewModel.saveSecDescPropertySelected()); + saveTerDesc.selectedProperty().bindBidirectional(viewModel.saveTerDescPropertySelected()); + + } + + public void changeExportDescriptionToSave() { + exportInOriginalOrder.setText(Localization.lang("Save entries in their original order")); + exportInSpecifiedOrder.setText(Localization.lang("Save entries ordered as specified")); + exportInTableOrder.setText(Localization.lang("Save in current table sort order")); + } + + public void storeConfig() { + viewModel.storeConfigInPrefs(); + } + + public SaveOrderConfig getSaveOrderConfig() { + return viewModel.getSaveOrderConfig(); + } + +} diff --git a/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java new file mode 100644 index 00000000000..0846ee4866c --- /dev/null +++ b/src/main/java/org/jabref/gui/SaveOrderConfigDisplayViewModel.java @@ -0,0 +1,141 @@ +package org.jabref.gui; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ListProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; + +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.InternalBibtexFields; +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 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 BooleanProperty saveInOriginalProperty = new SimpleBooleanProperty(); + private final BooleanProperty saveInTableOrderProperty = new SimpleBooleanProperty(); + private final BooleanProperty saveInSpecifiedOrderProperty = new SimpleBooleanProperty(); + + private final PreferencesService prefs; + + public SaveOrderConfigDisplayViewModel(SaveOrderConfig config, PreferencesService prefs) { + this.prefs = prefs; + + List fieldNames = InternalBibtexFields.getAllPublicFieldNames(); + fieldNames.add(BibEntry.KEY_FIELD); + Collections.sort(fieldNames); + + priSortFieldsProperty.addAll(fieldNames); + secSortFieldsProperty.addAll(fieldNames); + terSortFieldsProperty.addAll(fieldNames); + + setSaveOrderConfig(config); + } + + public ListProperty priSortFieldsProperty() { + return priSortFieldsProperty; + } + + public ListProperty secSortFieldsProperty() { + return secSortFieldsProperty; + } + + 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); + + return saveOrderConfig; + } + + public void setSaveOrderConfig(SaveOrderConfig saveOrderConfig) { + Objects.requireNonNull(saveOrderConfig); + + savePriSortSelectedValueProperty.setValue(saveOrderConfig.getSortCriteria().get(0).field); + savePriDescPropertySelected.setValue(saveOrderConfig.getSortCriteria().get(0).descending); + saveSecSortSelectedValueProperty.setValue(saveOrderConfig.getSortCriteria().get(1).field); + saveSecDescPropertySelected.setValue(saveOrderConfig.getSortCriteria().get(1).descending); + saveTerSortSelectedValueProperty.setValue(saveOrderConfig.getSortCriteria().get(2).field); + saveTerDescPropertySelected.setValue(saveOrderConfig.getSortCriteria().get(2).descending); + + if (saveOrderConfig.saveInOriginalOrder()) { + saveInOriginalProperty.setValue(true); + } else if (saveOrderConfig.saveInSpecifiedOrder()) { + saveInSpecifiedOrderProperty.setValue(true); + } else { + saveInTableOrderProperty.setValue(true); + } + + } + + private String getSelectedItemAsLowerCaseTrim(StringProperty string) { + return string.getValue().toLowerCase(Locale.ROOT).trim(); + } + + public BooleanProperty savePriDescPropertySelected() { + return savePriDescPropertySelected; + } + + public BooleanProperty saveSecDescPropertySelected() { + return saveSecDescPropertySelected; + } + + public BooleanProperty saveTerDescPropertySelected() { + return saveTerDescPropertySelected; + } + + public StringProperty savePriSortSelectedValueProperty() { + return savePriSortSelectedValueProperty; + } + + public StringProperty saveSecSortSelectedValueProperty() { + return saveSecSortSelectedValueProperty; + } + + public StringProperty saveTerSortSelectedValueProperty() { + return saveTerSortSelectedValueProperty; + } + + public void storeConfigInPrefs() { + prefs.storeExportSaveOrder(this.getSaveOrderConfig()); + } + + public BooleanProperty saveInOriginalProperty() { + return saveInOriginalProperty; + } + + public BooleanProperty saveInTableOrderProperty() { + return saveInTableOrderProperty; + } + + public BooleanProperty saveInSpecifiedOrderProperty() { + return this.saveInSpecifiedOrderProperty; + } +} diff --git a/src/main/java/org/jabref/gui/SidePaneManager.java b/src/main/java/org/jabref/gui/SidePaneManager.java index eef7f01098b..324810dd6ed 100644 --- a/src/main/java/org/jabref/gui/SidePaneManager.java +++ b/src/main/java/org/jabref/gui/SidePaneManager.java @@ -8,7 +8,6 @@ import java.util.stream.Stream; import org.jabref.Globals; -import org.jabref.gui.collab.FileUpdatePanel; import org.jabref.gui.groups.GroupSidePane; import org.jabref.gui.importer.fetcher.WebSearchPane; import org.jabref.gui.openoffice.OpenOfficeSidePanel; @@ -31,10 +30,9 @@ public SidePaneManager(JabRefPreferences preferences, JabRefFrame frame) { OpenOfficePreferences openOfficePreferences = preferences.getOpenOfficePreferences(); Stream.of( - new FileUpdatePanel(this), - new GroupSidePane(this, preferences, frame.getDialogService()), - new WebSearchPane(this, preferences, frame), - new OpenOfficeSidePanel(this, preferences, frame)) + new GroupSidePane(this, preferences, frame.getDialogService()), + new WebSearchPane(this, preferences, frame), + new OpenOfficeSidePanel(this, preferences, frame)) .forEach(pane -> components.put(pane.getType(), pane)); if (preferences.getBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE)) { diff --git a/src/main/java/org/jabref/gui/SidePaneType.java b/src/main/java/org/jabref/gui/SidePaneType.java index cd60411cf61..01cec0cedb1 100644 --- a/src/main/java/org/jabref/gui/SidePaneType.java +++ b/src/main/java/org/jabref/gui/SidePaneType.java @@ -4,5 +4,7 @@ * Definition of all possible components in the side pane. */ public enum SidePaneType { - OPEN_OFFICE, WEB_SEARCH, FILE_UPDATE_NOTIFICATION, GROUPS + OPEN_OFFICE, + WEB_SEARCH, + GROUPS } diff --git a/src/main/java/org/jabref/gui/StringDialog.java b/src/main/java/org/jabref/gui/StringDialog.java deleted file mode 100644 index 1169b1f7dce..00000000000 --- a/src/main/java/org/jabref/gui/StringDialog.java +++ /dev/null @@ -1,455 +0,0 @@ -package org.jabref.gui; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Container; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.DefaultCellEditor; -import javax.swing.InputMap; -import javax.swing.JComponent; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.JTextField; -import javax.swing.JToolBar; -import javax.swing.LayoutFocusTraversalPolicy; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableColumnModel; -import javax.swing.undo.CompoundEdit; - -import org.jabref.Globals; -import org.jabref.gui.actions.Actions; -import org.jabref.gui.help.HelpAction; -import org.jabref.gui.icon.IconTheme; -import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.undo.UndoableInsertString; -import org.jabref.gui.undo.UndoableRemoveString; -import org.jabref.gui.undo.UndoableStringChange; -import org.jabref.gui.util.WindowLocation; -import org.jabref.logic.bibtex.InvalidFieldValueException; -import org.jabref.logic.bibtex.LatexFieldFormatter; -import org.jabref.logic.bibtex.comparator.BibtexStringComparator; -import org.jabref.logic.help.HelpFile; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.database.KeyCollisionException; -import org.jabref.model.entry.BibtexString; -import org.jabref.preferences.JabRefPreferences; - -class StringDialog extends JabRefDialog { - - private static final String STRINGS_TITLE = Localization.lang("Strings for library"); - // A reference to the entry this object works on. - private final BibDatabase base; - private final BasePanel panel; - private final StringTable table; - private final HelpAction helpAction; - - private final SaveDatabaseAction saveAction = new SaveDatabaseAction(this); - - // The action concerned with closing the window. - private final CloseAction closeAction = new CloseAction(); - private List strings; - - - public StringDialog(JabRefFrame frame, BasePanel panel, BibDatabase base) { - super(StringDialog.class); - this.panel = panel; - this.base = base; - - sortStrings(); - - helpAction = new HelpAction(Localization.lang("Help"), HelpFile.STRING_EDITOR); - - addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - closeAction.actionPerformed(null); - } - }); - - // We replace the default FocusTraversalPolicy with a subclass - // that only allows the StringTable to gain keyboard focus. - setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() { - - @Override - protected boolean accept(Component c) { - return super.accept(c) && (c instanceof StringTable); - } - }); - - JPanel pan = new JPanel(); - GridBagLayout gbl = new GridBagLayout(); - pan.setLayout(gbl); - GridBagConstraints con = new GridBagConstraints(); - con.fill = GridBagConstraints.BOTH; - con.weighty = 1; - con.weightx = 1; - - StringTableModel stm = new StringTableModel(this, base); - table = new StringTable(stm); - if (!base.hasNoStrings()) { - table.setRowSelectionInterval(0, 0); - } - - gbl.setConstraints(table.getPane(), con); - pan.add(table.getPane()); - - JToolBar tlb = new OSXCompatibleToolbar(); - InputMap im = tlb.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - ActionMap am = tlb.getActionMap(); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.STRING_DIALOG_ADD_STRING), "add"); - NewStringAction newStringAction = new NewStringAction(this); - am.put("add", newStringAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.STRING_DIALOG_REMOVE_STRING), "remove"); - RemoveStringAction removeStringAction = new RemoveStringAction(this); - am.put("remove", removeStringAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE), "save"); - am.put("save", saveAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", closeAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.HELP), "help"); - am.put("help", helpAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.UNDO), "undo"); - UndoAction undoAction = new UndoAction(); - am.put("undo", undoAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.REDO), "redo"); - RedoAction redoAction = new RedoAction(); - am.put("redo", redoAction); - - tlb.add(newStringAction); - tlb.add(removeStringAction); - tlb.addSeparator(); - tlb.add(helpAction); - Container conPane = getContentPane(); - conPane.add(tlb, BorderLayout.NORTH); - conPane.add(pan, BorderLayout.CENTER); - - setTitle(STRINGS_TITLE + ": " - + panel.getBibDatabaseContext().getDatabaseFile().map(File::getName).orElse(GUIGlobals.UNTITLED_TITLE)); - WindowLocation pw = new WindowLocation(this, JabRefPreferences.STRINGS_POS_X, JabRefPreferences.STRINGS_POS_Y, - JabRefPreferences.STRINGS_SIZE_X, JabRefPreferences.STRINGS_SIZE_Y); - pw.displayWindowAtStoredLocation(); - } - - private static boolean isNumber(String name) { - // A pure integer number cannot be used as a string label, - // since Bibtex will read it as a number. - try { - Integer.parseInt(name); - return true; - } catch (NumberFormatException ex) { - return false; - } - } - - private void sortStrings() { - // Rebuild our sorted set of strings: - strings = new ArrayList<>(); - for (String s : base.getStringKeySet()) { - strings.add(base.getString(s)); - } - Collections.sort(strings, new BibtexStringComparator(false)); - } - - public void refreshTable() { - sortStrings(); - table.revalidate(); - table.clearSelection(); - table.repaint(); - } - - public void saveDatabase() { - panel.runCommand(Actions.SAVE); - } - - public void assureNotEditing() { - if (table.isEditing()) { - int col = table.getEditingColumn(); - int row = table.getEditingRow(); - table.getCellEditor(row, col).stopCellEditing(); - } - } - - static class SaveDatabaseAction extends AbstractAction { - - private final StringDialog parent; - - - public SaveDatabaseAction(StringDialog parent) { - super("Save library", IconTheme.JabRefIcons.SAVE.getIcon()); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Save library")); - this.parent = parent; - } - - @Override - public void actionPerformed(ActionEvent e) { - parent.saveDatabase(); - } - } - - class StringTable extends JTable { - - private final JScrollPane sp = new JScrollPane(this); - - - public StringTable(StringTableModel stm) { - super(stm); - setShowVerticalLines(true); - setShowHorizontalLines(true); - setColumnSelectionAllowed(true); - DefaultCellEditor dce = new DefaultCellEditor(new JTextField()); - dce.setClickCountToStart(2); - setDefaultEditor(String.class, dce); - TableColumnModel cm = getColumnModel(); - cm.getColumn(0).setPreferredWidth(800); - cm.getColumn(1).setPreferredWidth(2000); - getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - getActionMap().put("close", closeAction); - getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.HELP), "help"); - getActionMap().put("help", helpAction); - } - - public JComponent getPane() { - return sp; - } - - } - - class StringTableModel extends AbstractTableModel { - - private final BibDatabase tbase; - private final StringDialog parent; - - - public StringTableModel(StringDialog parent, BibDatabase base) { - this.parent = parent; - this.tbase = base; - } - - @Override - public Object getValueAt(int row, int col) { - return col == 0 ? strings.get(row).getName() : strings.get(row).getContent(); - } - - @Override - public void setValueAt(Object value, int row, int col) { - if (col == 0) { - // Change name of string. - if (!value.equals(strings.get(row).getName())) { - if (tbase.hasStringLabel((String) value)) { - JOptionPane.showMessageDialog(parent, Localization.lang("A string with that label already exists"), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - } else if (((String) value).contains(" ")) { - JOptionPane.showMessageDialog(parent, Localization.lang("The label of the string cannot contain spaces."), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - } else if (((String) value).contains("#")) { - JOptionPane.showMessageDialog(parent, Localization.lang("The label of the string cannot contain the '#' character."), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - } else if (isNumber((String) value)) { - JOptionPane.showMessageDialog(parent, Localization.lang("The label of the string cannot be a number."), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - } else { - // Store undo information. - BibtexString subject = strings.get(row); - panel.getUndoManager().addEdit( - new UndoableStringChange(panel, subject, true, subject.getName(), (String) value)); - subject.setName((String) value); - panel.markBaseChanged(); - refreshTable(); - } - } - } else { - // Change content of string. - BibtexString subject = strings.get(row); - - if (!value.equals(subject.getContent())) { - try { - new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()) - .format((String) value, "__dummy"); - } catch (InvalidFieldValueException ex) { - return; - } - // Store undo information. - panel.getUndoManager().addEdit( - new UndoableStringChange(panel, subject, false, subject.getContent(), (String) value)); - - subject.setContent((String) value); - panel.markBaseChanged(); - } - } - } - - @Override - public int getColumnCount() { - return 2; - } - - @Override - public int getRowCount() { - return strings.size(); - } - - @Override - public String getColumnName(int col) { - return col == 0 ? Localization.lang("Label") : - Localization.lang("Content"); - } - - @Override - public boolean isCellEditable(int row, int col) { - return true; - } - } - - class CloseAction extends AbstractAction { - - public CloseAction() { - super("Close window"); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Close dialog")); - } - - @Override - public void actionPerformed(ActionEvent e) { - panel.stringsClosing(); - dispose(); - } - } - - class NewStringAction extends AbstractAction { - - private final StringDialog parent; - - - public NewStringAction(StringDialog parent) { - super("New string", IconTheme.JabRefIcons.ADD.getIcon()); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("New string")); - this.parent = parent; - } - - @Override - public void actionPerformed(ActionEvent e) { - String name = JOptionPane.showInputDialog(parent, Localization.lang("Please enter the string's label")); - if (name == null) { - return; - } - if (isNumber(name)) { - JOptionPane.showMessageDialog(parent, Localization.lang("The label of the string cannot be a number."), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - return; - } - if (name.contains("#")) { - JOptionPane.showMessageDialog(parent, Localization.lang("The label of the string cannot contain the '#' character."), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - return; - } - if (name.contains(" ")) { - JOptionPane.showMessageDialog(parent, Localization.lang("The label of the string cannot contain spaces."), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - return; - } - try { - BibtexString bs = new BibtexString(name, ""); - - // Store undo information: - panel.getUndoManager().addEdit(new UndoableInsertString(panel, panel.getDatabase(), bs)); - - base.addString(bs); - refreshTable(); - panel.markBaseChanged(); - } catch (KeyCollisionException ex) { - JOptionPane.showMessageDialog(parent, - Localization.lang("A string with that label already exists"), - Localization.lang("Label"), JOptionPane.ERROR_MESSAGE); - } - } - } - - class RemoveStringAction extends AbstractAction { - - private final StringDialog parent; - - - public RemoveStringAction(StringDialog parent) { - super("Remove selected strings", IconTheme.JabRefIcons.REMOVE.getIcon()); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Remove selected strings")); - this.parent = parent; - } - - @Override - public void actionPerformed(ActionEvent e) { - int[] sel = table.getSelectedRows(); - if (sel.length > 0) { - - // Make sure no cell is being edited, as caused by the - // keystroke. This makes the content hang on the screen. - assureNotEditing(); - - String msg = (sel.length > 1 ? Localization.lang("Really delete the %0 selected entries?", - Integer.toString(sel.length)) : Localization.lang("Really delete the selected entry?")); - int answer = JOptionPane.showConfirmDialog(parent, msg, Localization.lang("Delete strings"), - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - if (answer == JOptionPane.YES_OPTION) { - CompoundEdit ce = new CompoundEdit(); - for (int i = sel.length - 1; i >= 0; i--) { - // Delete the strings backwards to avoid moving indexes. - - BibtexString subject = strings.get(sel[i]); - - // Store undo information: - ce.addEdit(new UndoableRemoveString(panel, base, subject)); - - base.removeString(subject.getId()); - } - ce.end(); - panel.getUndoManager().addEdit(ce); - - refreshTable(); - if (!base.hasNoStrings()) { - table.setRowSelectionInterval(0, 0); - } - } - } - } - } - - class UndoAction extends AbstractAction { - - public UndoAction() { - super("Undo", IconTheme.JabRefIcons.UNDO.getIcon()); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Undo")); - } - - @Override - public void actionPerformed(ActionEvent e) { - panel.runCommand(Actions.UNDO); - } - } - - class RedoAction extends AbstractAction { - - public RedoAction() { - super("Redo", IconTheme.JabRefIcons.REDO.getIcon()); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Redo")); - } - - @Override - public void actionPerformed(ActionEvent e) { - panel.runCommand(Actions.REDO); - } - } -} diff --git a/src/main/java/org/jabref/gui/WaitForSaveFinishedDialog.java b/src/main/java/org/jabref/gui/WaitForSaveFinishedDialog.java new file mode 100644 index 00000000000..f8758ab8e1e --- /dev/null +++ b/src/main/java/org/jabref/gui/WaitForSaveFinishedDialog.java @@ -0,0 +1,43 @@ +package org.jabref.gui; + +import java.util.List; + +import javafx.concurrent.Task; + +import org.jabref.logic.l10n.Localization; + +/** + * Dialog shown when closing of application needs to wait for a save operation to finish. + */ +public class WaitForSaveFinishedDialog { + + private final DialogService dialogService; + + public WaitForSaveFinishedDialog(DialogService dialogService) { + this.dialogService = dialogService; + } + + public void showAndWait(List basePanels) { + if (basePanels.stream().anyMatch(BasePanel::isSaving)) { + Task waitForSaveFinished = new Task() { + @Override + protected Void call() throws Exception { + while (basePanels.stream().anyMatch(BasePanel::isSaving)) { + if (isCancelled()) { + return null; + } else { + Thread.sleep(100); + } + } + return null; + } + }; + + dialogService.showProgressDialogAndWait( + Localization.lang("Please wait..."), + Localization.lang("Waiting for save operation to finish") + "...", + waitForSaveFinished + ); + } + } +} diff --git a/src/main/java/org/jabref/gui/WaitForSaveOperation.java b/src/main/java/org/jabref/gui/WaitForSaveOperation.java deleted file mode 100644 index 86b2e0a2f8b..00000000000 --- a/src/main/java/org/jabref/gui/WaitForSaveOperation.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.jabref.gui; - -import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JProgressBar; -import javax.swing.Timer; - -import org.jabref.logic.l10n.Localization; - -import com.jgoodies.forms.builder.ButtonBarBuilder; - -/** - * Dialog shown when closing of application needs to wait for a save operation to finish. - */ -public class WaitForSaveOperation implements ActionListener { - - private final JabRefFrame frame; - private final JDialog diag; - private final Timer t = new Timer(500, this); - private boolean canceled; - - - public WaitForSaveOperation(JabRefFrame frame) { - this.frame = frame; - - JButton cancel = new JButton(Localization.lang("Cancel")); - JProgressBar prog = new JProgressBar(0); - prog.setIndeterminate(true); - prog.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - diag = new JDialog((JFrame) null, Localization.lang("Please wait..."), true); - - ButtonBarBuilder bb = new ButtonBarBuilder(); - bb.addGlue(); - bb.addButton(cancel); - bb.addGlue(); - cancel.addActionListener(e -> { - canceled = true; - t.stop(); - diag.dispose(); - }); - - JLabel message = new JLabel(Localization.lang("Waiting for save operation to finish") + "..."); - message.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - diag.getContentPane().add(message, BorderLayout.NORTH); - diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); - diag.getContentPane().add(prog, BorderLayout.CENTER); - diag.pack(); - } - - public void show() { - t.start(); - diag.setVisible(true); - - } - - public boolean canceled() { - return canceled; - } - - @Override - public void actionPerformed(ActionEvent actionEvent) { - boolean anySaving = false; - for (BasePanel basePanel : frame.getBasePanelList()) { - if (basePanel.isSaving()) { - anySaving = true; - break; - } - } - if (!anySaving) { - t.stop(); - diag.dispose(); - } - } -} diff --git a/src/main/java/org/jabref/gui/WrapLayout.java b/src/main/java/org/jabref/gui/WrapLayout.java deleted file mode 100644 index 999c7abd3f0..00000000000 --- a/src/main/java/org/jabref/gui/WrapLayout.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.jabref.gui; - -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Insets; - -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; - -/** - * FlowLayout subclass that fully supports wrapping of components. - */ -public class WrapLayout extends FlowLayout { - /** - * Constructs a new WrapLayout with a left - * alignment and a default 5-unit horizontal and vertical gap. - */ - public WrapLayout() { - super(); - } - - /** - * Constructs a new FlowLayout with the specified - * alignment and a default 5-unit horizontal and vertical gap. - * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. - * @param align the alignment value - */ - public WrapLayout(int align) { - super(align); - } - - /** - * Creates a new flow layout manager with the indicated alignment - * and the indicated horizontal and vertical gaps. - *

- * The value of the alignment argument must be one of - * WrapLayout, WrapLayout, - * or WrapLayout. - * @param align the alignment value - * @param hgap the horizontal gap between components - * @param vgap the vertical gap between components - */ - public WrapLayout(int align, int hgap, int vgap) { - super(align, hgap, vgap); - } - - /** - * Returns the preferred dimensions for this layout given the - * visible components in the specified target container. - * @param target the component which needs to be laid out - * @return the preferred dimensions to lay out the - * subcomponents of the specified container - */ - @Override - public Dimension preferredLayoutSize(Container target) { - return layoutSize(target, true); - } - - /** - * Returns the minimum dimensions needed to layout the visible - * components contained in the specified target container. - * @param target the component which needs to be laid out - * @return the minimum dimensions to lay out the - * subcomponents of the specified container - */ - @Override - public Dimension minimumLayoutSize(Container target) { - Dimension minimum = layoutSize(target, false); - minimum.width -= (getHgap() + 1); - return minimum; - } - - /** - * Returns the minimum or preferred dimension needed to layout the target - * container. - * - * @param target target to get layout size for - * @param preferred should preferred size be calculated - * @return the dimension to layout the target container - */ - private Dimension layoutSize(Container target, boolean preferred) { - synchronized (target.getTreeLock()) { - // Each row must fit with the width allocated to the container. - // When the container width = 0, the preferred width of the container - // has not yet been calculated so lets ask for the maximum. - - int targetWidth = target.getSize().width; - - if (targetWidth == 0) { - targetWidth = Integer.MAX_VALUE; - } - - int hgap = getHgap(); - int vgap = getVgap(); - Insets insets = target.getInsets(); - int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); - int maxWidth = targetWidth - horizontalInsetsAndGap; - - // Fit components into the allowed width - - Dimension dim = new Dimension(0, 0); - int rowWidth = 0; - int rowHeight = 0; - - int nmembers = target.getComponentCount(); - - for (int i = 0; i < nmembers; i++) { - Component m = target.getComponent(i); - - if (m.isVisible()) { - Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); - - if (d != null) { - // Can't add the component to current row. Start a new row. - - if ((rowWidth + d.width) > maxWidth) { - addRow(dim, rowWidth, rowHeight); - rowWidth = 0; - rowHeight = 0; - } - - // Add a horizontal gap for all components after the first - - if (rowWidth != 0) { - rowWidth += hgap; - } - - rowWidth += d.width; - rowHeight = Math.max(rowHeight, d.height); - } - } - } - - addRow(dim, rowWidth, rowHeight); - - dim.width += horizontalInsetsAndGap; - dim.height += insets.top + insets.bottom + (vgap * 2); - - // When using a scroll pane or the DecoratedLookAndFeel we need to - // make sure the preferred size is less than the size of the - // target container so shrinking the container size works - // correctly. Removing the horizontal gap is an easy way to do this. - - Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); - - if (scrollPane != null) { - dim.width -= (hgap + 1); - } - - return dim; - } - } - - /* - * A new row has been completed. Use the dimensions of this row - * to update the preferred size for the container. - * - * @param dim update the width and height when appropriate - * @param rowWidth the width of the row to add - * @param rowHeight the height of the row to add - */ - private void addRow(Dimension dim, int rowWidth, int rowHeight) { - dim.width = Math.max(dim.width, rowWidth); - - if (dim.height > 0) { - dim.height += getVgap(); - } - - dim.height += rowHeight; - } -} diff --git a/src/main/java/org/jabref/gui/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java index 8792b7e314d..9cd9edc4fe3 100644 --- a/src/main/java/org/jabref/gui/actions/ActionFactory.java +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -5,6 +5,7 @@ import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ButtonBase; +import javafx.scene.control.CheckMenuItem; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; @@ -43,6 +44,14 @@ public MenuItem createMenuItem(Action action, Command command) { return menuItem; } + public CheckMenuItem createCheckMenuItem(Action action, Command command, boolean selected) { + CheckMenuItem checkMenuItem = ActionUtils.createCheckMenuItem(new JabRefAction(action, command, keyBindingRepository)); + checkMenuItem.setSelected(selected); + setGraphic(checkMenuItem, action); + + return checkMenuItem; + } + public Menu createMenu(Action action) { Menu menu = ActionUtils.createMenu(new JabRefAction(action, keyBindingRepository)); diff --git a/src/main/java/org/jabref/gui/actions/Actions.java b/src/main/java/org/jabref/gui/actions/Actions.java index 4a72f33a45f..f115eda059c 100644 --- a/src/main/java/org/jabref/gui/actions/Actions.java +++ b/src/main/java/org/jabref/gui/actions/Actions.java @@ -8,7 +8,6 @@ public enum Actions { ABBREVIATE_ISO, ABBREVIATE_MEDLINE, ADD_FILE_LINK, - ADD_TO_GROUP, CLEANUP, COPY, COPY_CITATION_ASCII_DOC, @@ -34,7 +33,6 @@ public enum Actions { MERGE_ENTRIES, MERGE_WITH_FETCHED_ENTRY, NEXT_PREVIEW_STYLE, - MOVE_TO_GROUP, OPEN_CONSOLE, OPEN_EXTERNAL_FILE, OPEN_FOLDER, @@ -43,9 +41,7 @@ public enum Actions { PREVIOUS_PREVIEW_STYLE, PULL_CHANGES_FROM_SHARED_DATABASE, REDO, - REMOVE_FROM_GROUP, REPLACE_ALL, - RESOLVE_DUPLICATE_KEYS, SAVE, SAVE_AS, SAVE_SELECTED_AS_PLAIN, diff --git a/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java b/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java deleted file mode 100644 index 7b77c9f59b4..00000000000 --- a/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.jabref.gui.actions; - -import java.util.List; - -import javax.swing.JDialog; -import javax.swing.JFrame; - -import org.jabref.JabRefExecutorService; -import org.jabref.JabRefGUI; -import org.jabref.gui.externalfiles.AutoSetLinks; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; - -/** - * This Action may only be used in a menu or button. - * Never in the entry editor. FileListEditor and EntryEditor have other ways to update the file links - */ -public class AutoLinkFilesAction extends SimpleCommand { - - public AutoLinkFilesAction() { - - } - - @Override - public void execute() { - List entries = JabRefGUI.getMainFrame().getCurrentBasePanel().getSelectedEntries(); - if (entries.isEmpty()) { - JabRefGUI.getMainFrame().getCurrentBasePanel() - .output(Localization.lang("This operation requires one or more entries to be selected.")); - return; - } - JDialog diag = new JDialog((JFrame) null, true); - final NamedCompound nc = new NamedCompound(Localization.lang("Automatically set file links")); - Runnable runnable = AutoSetLinks.autoSetLinks(entries, nc, null, - JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext(), e -> { - if (e.getID() > 0) { - // entry has been updated in Util.autoSetLinks, only treat nc and status message - if (nc.hasEdits()) { - nc.end(); - JabRefGUI.getMainFrame().getCurrentBasePanel().getUndoManager().addEdit(nc); - JabRefGUI.getMainFrame().getCurrentBasePanel().markBaseChanged(); - } - JabRefGUI.getMainFrame().output(Localization.lang("Finished automatically setting external links.")); - } else { - JabRefGUI.getMainFrame().output(Localization.lang("Finished automatically setting external links.") + " " - + Localization.lang("No files found.")); - } - } , diag); - JabRefExecutorService.INSTANCE.execute(runnable); - } -} diff --git a/src/main/java/org/jabref/gui/actions/ChangeTypeAction.java b/src/main/java/org/jabref/gui/actions/ChangeTypeAction.java deleted file mode 100644 index b7b907a662c..00000000000 --- a/src/main/java/org/jabref/gui/actions/ChangeTypeAction.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.jabref.gui.actions; - -import java.awt.event.ActionEvent; -import java.util.Collections; -import java.util.List; - -import javax.swing.AbstractAction; -import javax.swing.undo.UndoManager; - -import javafx.scene.control.MenuItem; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableChangeType; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.EntryType; - -public class ChangeTypeAction extends AbstractAction { - - private final String type; - private final BasePanel panel; - - public ChangeTypeAction(EntryType type, BasePanel bp) { - super(type.getName()); - this.type = type.getName(); - panel = bp; - } - - @Override - public void actionPerformed(ActionEvent evt) { - panel.changeTypeOfSelectedEntries(type); - } - - public static MenuItem as(EntryType type, BibEntry entry, UndoManager undoManager) { - return as(type, Collections.singletonList(entry), undoManager); - } - - public static MenuItem as(EntryType type, List entries, UndoManager undoManager) { - MenuItem menuItem = new MenuItem(type.getName()); - menuItem.setOnAction(event -> { - NamedCompound compound = new NamedCompound(Localization.lang("Change entry type")); - for (BibEntry entry : entries) { - entry.setType(type) - .ifPresent(change -> compound.addEdit(new UndoableChangeType(change))); - } - - undoManager.addEdit(compound); - }); - return menuItem; - } -} diff --git a/src/main/java/org/jabref/gui/actions/CleanupAction.java b/src/main/java/org/jabref/gui/actions/CleanupAction.java index 648af8313b7..4a0f89e8b61 100644 --- a/src/main/java/org/jabref/gui/actions/CleanupAction.java +++ b/src/main/java/org/jabref/gui/actions/CleanupAction.java @@ -10,6 +10,7 @@ import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.cleanup.CleanupWorker; import org.jabref.logic.l10n.Localization; @@ -21,15 +22,17 @@ public class CleanupAction implements BaseAction { private final BasePanel panel; private final DialogService dialogService; + private final TaskExecutor taskExecutor; private boolean isCanceled; private int modifiedEntriesCount; private final JabRefPreferences preferences; - public CleanupAction(BasePanel panel, JabRefPreferences preferences) { + public CleanupAction(BasePanel panel, JabRefPreferences preferences, TaskExecutor taskExecutor) { this.panel = panel; this.preferences = preferences; this.dialogService = panel.frame().getDialogService(); + this.taskExecutor = taskExecutor; } @Override @@ -61,7 +64,7 @@ public void action() { BackgroundTask.wrap(() -> cleanup(chosenPreset.get())) .onSuccess(result -> showResults()) - .executeWith(Globals.TASK_EXECUTOR); + .executeWith(taskExecutor); } } @@ -73,7 +76,7 @@ public void init() { isCanceled = true; return; } - panel.output(Localization.lang("Doing a cleanup for %0 entries...", + dialogService.notify(Localization.lang("Doing a cleanup for %0 entries...", Integer.toString(panel.getSelectedEntries().size()))); } @@ -117,7 +120,7 @@ private void showResults() { message = Localization.lang("%0 entries needed a clean up", Integer.toString(modifiedEntriesCount)); break; } - panel.output(message); + dialogService.notify(message); } private void cleanup(CleanupPreset cleanupPreset) { diff --git a/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java b/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java index 6f55af1e27b..49c8a5f46ec 100644 --- a/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java @@ -36,7 +36,7 @@ public void action() throws Exception { List entriesWithKey = entries.stream().filter(BibEntry::hasCiteKey).collect(Collectors.toList()); if (entriesWithKey.isEmpty()) { - JabRefGUI.getMainFrame().output(Localization.lang("None of the selected entries have BibTeX keys.")); + JabRefGUI.getMainFrame().getDialogService().notify(Localization.lang("None of the selected entries have BibTeX keys.")); return; } @@ -53,9 +53,9 @@ public void action() throws Exception { int toCopy = entries.size(); if (copied == toCopy) { // All entries had keys. - JabRefGUI.getMainFrame().output((entries.size() > 1 ? Localization.lang("Copied keys") : Localization.lang("Copied key")) + '.'); + JabRefGUI.getMainFrame().getDialogService().notify((entries.size() > 1 ? Localization.lang("Copied keys") : Localization.lang("Copied key")) + '.'); } else { - JabRefGUI.getMainFrame().output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", + JabRefGUI.getMainFrame().getDialogService().notify(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", Long.toString(toCopy - copied), Integer.toString(toCopy))); } } diff --git a/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java b/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java index aa8ee344abe..e541cd58d5a 100644 --- a/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java @@ -1,10 +1,7 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; import java.util.Optional; -import javax.swing.AbstractAction; - import javafx.scene.control.TextArea; import org.jabref.Globals; @@ -15,31 +12,24 @@ /** * Copies the doi url to the clipboard */ -public class CopyDoiUrlAction extends AbstractAction { - - private TextArea component = null; - private String identifier; +public class CopyDoiUrlAction extends SimpleCommand { - public CopyDoiUrlAction(String identifier) { - super(Localization.lang("Copy DOI url")); - this.identifier = identifier; - } + private TextArea component; public CopyDoiUrlAction(TextArea component) { - this(component.getText()); this.component = component; } @Override - public void actionPerformed(ActionEvent e) { - identifier = component == null ? identifier : component.getText(); + public void execute() { + String identifier = component.getText(); Optional urlOptional = DOI.parse(identifier).map(DOI::getURIAsASCIIString); if (urlOptional.isPresent()) { Globals.clipboardManager.setContent(urlOptional.get()); - JabRefGUI.getMainFrame().output(Localization.lang("The link has been copied to the clipboard.")); + JabRefGUI.getMainFrame().getDialogService().notify(Localization.lang("The link has been copied to the clipboard.")); } else { - JabRefGUI.getMainFrame().output(Localization.lang("Invalid DOI: '%0'.", identifier)); + JabRefGUI.getMainFrame().getDialogService().notify(Localization.lang("Invalid DOI: '%0'.", identifier)); } } } diff --git a/src/main/java/org/jabref/gui/actions/DatabasePropertiesAction.java b/src/main/java/org/jabref/gui/actions/DatabasePropertiesAction.java deleted file mode 100644 index 564b6c5cc2f..00000000000 --- a/src/main/java/org/jabref/gui/actions/DatabasePropertiesAction.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.jabref.gui.actions; - -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.dbproperties.DatabasePropertiesDialog; - -public class DatabasePropertiesAction extends SimpleCommand { - - private final JabRefFrame frame; - - public DatabasePropertiesAction(JabRefFrame frame) { - this.frame = frame; - } - - @Override - public void execute() { - DatabasePropertiesDialog propertiesDialog = new DatabasePropertiesDialog(frame.getCurrentBasePanel()); - propertiesDialog.updateEnableStatus(); - propertiesDialog.setVisible(true); - } - -} diff --git a/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java b/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java index 82bbc9123ce..c5ea26bb8cb 100644 --- a/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java +++ b/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java @@ -1,12 +1,12 @@ package org.jabref.gui.actions; -import org.jabref.gui.externalfiletype.ExternalFileTypeEditor; +import org.jabref.gui.externalfiletype.CustomizeExternalFileTypesDialog; public class EditExternalFileTypesAction extends SimpleCommand { @Override public void execute() { - ExternalFileTypeEditor editor = new ExternalFileTypeEditor(); - editor.show(); + CustomizeExternalFileTypesDialog editor = new CustomizeExternalFileTypesDialog(); + editor.showAndWait(); } } diff --git a/src/main/java/org/jabref/gui/actions/GenerateBibtexKeyAction.java b/src/main/java/org/jabref/gui/actions/GenerateBibtexKeyAction.java index 90b61800215..744db49711c 100644 --- a/src/main/java/org/jabref/gui/actions/GenerateBibtexKeyAction.java +++ b/src/main/java/org/jabref/gui/actions/GenerateBibtexKeyAction.java @@ -33,7 +33,7 @@ public void init() { Localization.lang("First select the entries you want keys to be generated for.")); return; } - basePanel.output(formatOutputMessage(Localization.lang("Generating BibTeX key for"), entries.size())); + dialogService.notify(formatOutputMessage(Localization.lang("Generating BibTeX key for"), entries.size())); } public static boolean confirmOverwriteKeys(DialogService dialogService) { @@ -87,7 +87,7 @@ private void generateKeys() { } basePanel.markBaseChanged(); - basePanel.output(formatOutputMessage(Localization.lang("Generated BibTeX key for"), entries.size())); + dialogService.notify(formatOutputMessage(Localization.lang("Generated BibTeX key for"), entries.size())); } private String formatOutputMessage(String start, int count) { diff --git a/src/main/java/org/jabref/gui/actions/LibraryPropertiesAction.java b/src/main/java/org/jabref/gui/actions/LibraryPropertiesAction.java new file mode 100644 index 00000000000..1b2299e3f06 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/LibraryPropertiesAction.java @@ -0,0 +1,24 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.DialogService; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.libraryproperties.LibraryPropertiesDialogView; + +public class LibraryPropertiesAction extends SimpleCommand { + + private final JabRefFrame frame; + private final DialogService dialogService; + + public LibraryPropertiesAction(JabRefFrame frame, DialogService dialogService) { + this.frame = frame; + this.dialogService = dialogService; + } + + @Override + public void execute() { + LibraryPropertiesDialogView propertiesDialog = new LibraryPropertiesDialogView(frame.getCurrentBasePanel(), dialogService); + propertiesDialog.showAndWait(); + + } + +} diff --git a/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java b/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java index f1f6e6f0846..a2d6c7372d9 100644 --- a/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java +++ b/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java @@ -12,6 +12,7 @@ import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.IdFetcher; import org.jabref.logic.l10n.Localization; @@ -39,7 +40,7 @@ public LookupIdentifierAction(JabRefFrame frame, IdFetcher fetcher) { public void execute() { try { BackgroundTask.wrap(this::lookupIdentifiers) - .onSuccess(frame::output) + .onSuccess(frame.getDialogService()::notify) .executeWith(Globals.TASK_EXECUTOR); } catch (Exception e) { LOGGER.error("Problem running ID Worker", e); @@ -84,8 +85,9 @@ private String lookupIdentifiers() { int foundCount = 0; for (BibEntry bibEntry : bibEntries) { count++; - frame.output(Localization.lang("Looking up %0... - entry %1 out of %2 - found %3", - fetcher.getIdentifierName(), Integer.toString(count), totalCount, Integer.toString(foundCount))); + final String statusMessage = Localization.lang("Looking up %0... - entry %1 out of %2 - found %3", + fetcher.getIdentifierName(), Integer.toString(count), totalCount, Integer.toString(foundCount)); + DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().notify(statusMessage)); Optional identifier = Optional.empty(); try { identifier = fetcher.findIdentifier(bibEntry); @@ -97,8 +99,9 @@ private String lookupIdentifiers() { if (fieldChange.isPresent()) { namedCompound.addEdit(new UndoableFieldChange(fieldChange.get())); foundCount++; - frame.output(Localization.lang("Looking up %0... - entry %1 out of %2 - found %3", - Integer.toString(count), totalCount, Integer.toString(foundCount))); + final String nextStatusMessage = Localization.lang("Looking up %0... - entry %1 out of %2 - found %3", + fetcher.getIdentifierName(), Integer.toString(count), totalCount, Integer.toString(foundCount)); + DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().notify(nextStatusMessage)); } } } diff --git a/src/main/java/org/jabref/gui/actions/ManageContentSelectorAction.java b/src/main/java/org/jabref/gui/actions/ManageContentSelectorAction.java new file mode 100644 index 00000000000..31e2b1e1149 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ManageContentSelectorAction.java @@ -0,0 +1,29 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.contentselector.ContentSelectorDialogView; +import org.jabref.logic.l10n.Localization; + +public class ManageContentSelectorAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public ManageContentSelectorAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + BasePanel basePanel = jabRefFrame.getCurrentBasePanel(); + if (noActiveConnectionExists(basePanel)) { + jabRefFrame.getDialogService().showErrorDialogAndWait(Localization.lang("Active database connection do not exists!")); + return; + } + new ContentSelectorDialogView(basePanel).showAndWait(); + } + + private boolean noActiveConnectionExists(BasePanel basePanel) { + return basePanel == null || basePanel.getBibDatabaseContext() == null; + } +} diff --git a/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java b/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java deleted file mode 100644 index 0af7a02f91c..00000000000 --- a/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java +++ /dev/null @@ -1,356 +0,0 @@ -package org.jabref.gui.actions; - -import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.util.Enumeration; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.DefaultListModel; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JList; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.JTextField; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableFieldChange; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.specialfields.SpecialFieldsUtils; -import org.jabref.model.FieldChange; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.Keyword; -import org.jabref.model.entry.KeywordList; -import org.jabref.model.strings.StringUtil; - -import com.jgoodies.forms.builder.ButtonBarBuilder; -import com.jgoodies.forms.builder.FormBuilder; -import com.jgoodies.forms.layout.FormLayout; - -/** - * An Action for launching keyword managing dialog - * - */ -public class ManageKeywordsAction extends SimpleCommand { - - private final JabRefFrame frame; - private final KeywordList sortedKeywordsOfAllEntriesBeforeUpdateByUser = new KeywordList(); - private JDialog diag; - private DefaultListModel keywordListModel; - private JRadioButton intersectKeywords; - private JRadioButton mergeKeywords; - private boolean canceled; - - - public ManageKeywordsAction(JabRefFrame frame) { - this.frame = frame; - } - - private void createDialog() { - if (diag != null) { - return; - } - // keyword to add - JTextField keyword = new JTextField(); - - keywordListModel = new DefaultListModel<>(); - JList keywordList = new JList<>(keywordListModel); - keywordList.setVisibleRowCount(8); - JScrollPane kPane = new JScrollPane(keywordList); - - diag = new JDialog((JFrame) null, Localization.lang("Manage keywords"), true); - - JButton ok = new JButton(Localization.lang("OK")); - JButton cancel = new JButton(Localization.lang("Cancel")); - JButton add = new JButton(Localization.lang("Add")); - JButton remove = new JButton(Localization.lang("Remove")); - JButton replace = new JButton(Localization.lang("Replace")); - JButton join = new JButton(Localization.lang("Join")); - - join.setToolTipText(Localization.lang("Joins selected keywords and deletes selected keywords.")); - - keywordList.setVisibleRowCount(10); - - intersectKeywords = new JRadioButton(Localization.lang("Display keywords appearing in ALL entries")); - mergeKeywords = new JRadioButton(Localization.lang("Display keywords appearing in ANY entry")); - ButtonGroup group = new ButtonGroup(); - group.add(intersectKeywords); - group.add(mergeKeywords); - ActionListener stateChanged = e -> fillKeyWordList(); - intersectKeywords.addActionListener(stateChanged); - mergeKeywords.addActionListener(stateChanged); - intersectKeywords.setSelected(true); - - FormBuilder builder = FormBuilder.create().layout(new FormLayout("fill:200dlu:grow, pref, fill:pref", - "pref, 2dlu, pref, 1dlu, pref, 2dlu, fill:100dlu:grow, 4dlu, pref, 4dlu, pref, ")); - - builder.addSeparator(Localization.lang("Keywords of selected entries")).xyw(1, 1, 3); - builder.add(intersectKeywords).xyw(1, 3, 3); - builder.add(mergeKeywords).xyw(1, 5, 3); - builder.add(kPane).xywh(1, 7, 1, 3); - builder.add(join).xy(2,9); - builder.add(replace).xy(3, 9); - builder.add(keyword).xy(1, 11); - builder.add(add).xy(2, 11); - builder.add(remove).xy(3, 11); - - ButtonBarBuilder bb = new ButtonBarBuilder(); - bb.addGlue(); - bb.addButton(ok); - bb.addButton(cancel); - bb.addGlue(); - builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - ok.addActionListener(e -> { - canceled = false; - diag.dispose(); - }); - - Action cancelAction = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - canceled = true; - diag.dispose(); - } - }; - cancel.addActionListener(cancelAction); - - final ActionListener addActionListener = arg0 -> addButtonActionListener(keyword); - - add.addActionListener(addActionListener); - - final ActionListener removeActionListener = arg0 -> { - // keywordList.getSelectedIndices(); does not work, therefore we operate on the values - List values = keywordList.getSelectedValuesList(); - - for (Keyword val : values) { - keywordListModel.removeElement(val); - } - }; - - remove.addActionListener(removeActionListener); - - final ActionListener joinActionListener = arg0 -> { - List values = keywordList.getSelectedValuesList(); - String joinedKeyword = values.stream().map(currentKeyword -> currentKeyword.get()).collect(Collectors.joining(" ")); - this.addKeywordToKeywordListModel(joinedKeyword); - - for (Keyword val : values) { - this.keywordListModel.removeElement(val); - } - }; - - join.addActionListener(joinActionListener); - - final ActionListener replaceActionListener = arg0 -> { - List values = keywordList.getSelectedValuesList(); - - for (Keyword val : values) { - keywordListModel.removeElement(val); - } - addButtonActionListener(keyword); - }; - - replace.addActionListener(replaceActionListener); - - //enable a user to press Delete to delete a keyword - keywordList.addKeyListener(new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent arg0) { - if (arg0.getKeyCode() == KeyEvent.VK_DELETE) { - removeActionListener.actionPerformed(null); - } - } - }); - - //enable a user to press Enter to add a keyword - keyword.addKeyListener(new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - addActionListener.actionPerformed(null); - } - } - }); - - // Key bindings: - ActionMap am = builder.getPanel().getActionMap(); - InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", cancelAction); - - diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER); - diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); - } - - private void addButtonActionListener(JTextField keywordTextField) { - if (StringUtil.isBlank(keywordTextField.getText())) { - return; // nothing to add - } - addKeywordToKeywordListModel(keywordTextField.getText()); - keywordTextField.setText(null); - keywordTextField.requestFocusInWindow(); - - } - - /** - * Adds given keyword to the keyword list model - */ - private void addKeywordToKeywordListModel(String keyword) { - String keywordToAdd = Objects.requireNonNull(keyword).trim(); - Keyword newKeyword = new Keyword(keywordToAdd); - if (keywordListModel.isEmpty()) { - keywordListModel.addElement(newKeyword); - } else { - int idx = 0; - Keyword element = keywordListModel.getElementAt(idx); - while ((idx < keywordListModel.size()) && (element.compareTo(newKeyword) < 0)) { - idx++; - } - if (idx == keywordListModel.size()) { - // list is empty or word is greater than last word in list - keywordListModel.addElement(newKeyword); - } else if (element.compareTo(newKeyword) == 0) { - // nothing to do, word already in table - } else { - keywordListModel.add(idx, newKeyword); - } - } - } - - @Override - public void execute() { - BasePanel bp = frame.getCurrentBasePanel(); - if (bp == null) { - return; - } - if (bp.getSelectedEntries().isEmpty()) { - bp.output(Localization.lang("Select at least one entry to manage keywords.")); - return; - } - - // Lazy creation of the dialog: - createDialog(); - - canceled = true; - - fillKeyWordList(); - - diag.pack(); - diag.setVisible(true); - if (canceled) { - return; - } - - KeywordList keywordsToAdd = new KeywordList(); - KeywordList userSelectedKeywords = new KeywordList(); - // build keywordsToAdd and userSelectedKeywords in parallel - for (Enumeration keywords = keywordListModel.elements(); keywords.hasMoreElements();) { - Keyword keyword = keywords.nextElement(); - userSelectedKeywords.add(keyword); - if (!sortedKeywordsOfAllEntriesBeforeUpdateByUser.contains(keyword)) { - keywordsToAdd.add(keyword); - } - } - - KeywordList keywordsToRemove = new KeywordList(); - for (Keyword kword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) { - if (!userSelectedKeywords.contains(kword)) { - keywordsToRemove.add(kword); - } - } - - if (keywordsToAdd.isEmpty() && keywordsToRemove.isEmpty()) { - // nothing to be done if nothing is new and nothing is obsolete - return; - } - - if (Globals.prefs.isKeywordSyncEnabled() && !keywordsToAdd.isEmpty()) { - SpecialFieldsUtils.synchronizeSpecialFields(keywordsToAdd, keywordsToRemove); - } - - NamedCompound ce = updateKeywords(bp.getSelectedEntries(), keywordsToAdd, keywordsToRemove); - bp.getUndoManager().addEdit(ce); - bp.markBaseChanged(); - } - - private NamedCompound updateKeywords(List entries, KeywordList keywordsToAdd, - KeywordList keywordsToRemove) { - NamedCompound ce = new NamedCompound(Localization.lang("Update keywords")); - for (BibEntry entry : entries) { - KeywordList keywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter()); - - // update keywords - keywords.removeAll(keywordsToRemove); - keywords.addAll(keywordsToAdd); - - // put keywords back - Optional change = entry.putKeywords(keywords, Globals.prefs.getKeywordDelimiter()); - if (change.isPresent()) { - ce.addEdit(new UndoableFieldChange(change.get())); - } - - if (Globals.prefs.isKeywordSyncEnabled()) { - SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, Globals.prefs.getKeywordDelimiter()); - } - } - ce.end(); - return ce; - } - - private void fillKeyWordList() { - BasePanel bp = frame.getCurrentBasePanel(); - List entries = bp.getSelectedEntries(); - - // fill dialog with values - keywordListModel.clear(); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.clear(); - - if (mergeKeywords.isSelected()) { - for (BibEntry entry : entries) { - KeywordList separatedKeywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter()); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords); - } - } else { - assert intersectKeywords.isSelected(); - - // all keywords from first entry have to be added - BibEntry firstEntry = entries.get(0); - KeywordList separatedKeywords = firstEntry.getKeywords(Globals.prefs.getKeywordDelimiter()); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords); - - // for the remaining entries, intersection has to be used - // this approach ensures that one empty keyword list leads to an empty set of common keywords - for (int i = 1; i < entries.size(); i++) { - BibEntry entry = entries.get(i); - separatedKeywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter()); - sortedKeywordsOfAllEntriesBeforeUpdateByUser.retainAll(separatedKeywords); - } - } - for (Keyword keyword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) { - keywordListModel.addElement(keyword); - } - } - -} diff --git a/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java b/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java deleted file mode 100644 index c4f05f955cf..00000000000 --- a/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.jabref.gui.actions; - -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.protectedterms.ProtectedTermsDialog; -import org.jabref.logic.protectedterms.ProtectedTermsLoader; - -public class ManageProtectedTermsAction extends SimpleCommand { - - private final JabRefFrame jabRefFrame; - private final ProtectedTermsLoader termsLoader; - - public ManageProtectedTermsAction(JabRefFrame jabRefFrame, ProtectedTermsLoader termsLoader) { - this.jabRefFrame = jabRefFrame; - this.termsLoader = termsLoader; - } - @Override - public void execute() { - ProtectedTermsDialog protectTermsDialog = new ProtectedTermsDialog(jabRefFrame); - protectTermsDialog.setVisible(true); - - } - -} diff --git a/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java b/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java deleted file mode 100644 index b1bfa9f87d5..00000000000 --- a/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.jabref.gui.actions; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Icon; - -import org.jabref.gui.icon.IconTheme; - -/** - * This class extends {@link AbstractAction} with the ability to set - * the mnemonic key based on a '&' character inserted in front of - * the desired mnemonic letter. This is done by setting the action's - * name using putValue(NAME, actionname). - * This facilitates localized mnemonics. - */ -public abstract class MnemonicAwareAction extends AbstractAction { - - public MnemonicAwareAction() { } - - public MnemonicAwareAction(Icon icon) { - if (icon instanceof IconTheme.FontBasedIcon) { - putValue(Action.SMALL_ICON, ((IconTheme.FontBasedIcon) icon).createSmallIcon()); - putValue(Action.LARGE_ICON_KEY, icon); - } else { - putValue(Action.SMALL_ICON, icon); - } - } - - @Override - public void putValue(String key, Object value) { - if (key.equals(Action.NAME)) { - String name = value.toString(); - int i = name.indexOf('&'); - if (i >= 0) { - char mnemonic = Character.toUpperCase(name.charAt(i + 1)); - putValue(Action.MNEMONIC_KEY, (int) mnemonic); - value = name.substring(0, i) + name.substring(i + 1); - } else { - value = name; - } - } - super.putValue(key, value); - } -} diff --git a/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java b/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java index 90b2f8ced30..e00604e3a1b 100644 --- a/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java +++ b/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java @@ -24,6 +24,6 @@ public void execute() { BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX)); bibDatabaseContext.setMode(mode); jabRefFrame.addTab(bibDatabaseContext, true); - jabRefFrame.output(Localization.lang("New %0 library created.", mode.getFormattedName())); + jabRefFrame.getDialogService().notify(Localization.lang("New %0 library created.", mode.getFormattedName())); } } diff --git a/src/main/java/org/jabref/gui/actions/NewEntryFromPlainTextAction.java b/src/main/java/org/jabref/gui/actions/NewEntryFromPlainTextAction.java deleted file mode 100644 index b4c3faa9a2b..00000000000 --- a/src/main/java/org/jabref/gui/actions/NewEntryFromPlainTextAction.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.jabref.gui.actions; - -import org.jabref.gui.DialogService; -import org.jabref.gui.EntryTypeView; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.plaintextimport.TextInputDialog; -import org.jabref.logic.util.UpdateField; -import org.jabref.logic.util.UpdateFieldPreferences; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.EntryType; -import org.jabref.preferences.JabRefPreferences; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NewEntryFromPlainTextAction extends SimpleCommand { - - private static final Logger LOGGER = LoggerFactory.getLogger(NewEntryFromPlainTextAction.class); - - private final UpdateFieldPreferences prefs; - private final JabRefFrame jabRefFrame; - private final DialogService dialogService; - private final JabRefPreferences preferences; - - public NewEntryFromPlainTextAction(JabRefFrame jabRefFrame, UpdateFieldPreferences prefs, DialogService dialogService, JabRefPreferences preferences) { - this.jabRefFrame = jabRefFrame; - this.prefs = prefs; - this.dialogService = dialogService; - this.preferences = preferences; - - } - - @Override - public void execute() { - if (jabRefFrame.getBasePanelCount() <= 0) { - LOGGER.error("Action 'New entry' must be disabled when no database is open."); - return; - } - - EntryTypeView typeChoiceDialog = new EntryTypeView(jabRefFrame.getCurrentBasePanel(), dialogService, preferences); - EntryType selectedType = typeChoiceDialog.showAndWait().orElse(null); - if (selectedType == null) { - return; - } - BibEntry bibEntry = new BibEntry(selectedType); - - TextInputDialog tidialog = new TextInputDialog(jabRefFrame, bibEntry); - tidialog.setVisible(true); - if (tidialog.okPressed()) { - UpdateField.setAutomaticFields(bibEntry, false, false, prefs); - jabRefFrame.getCurrentBasePanel().insertEntry(bibEntry); - } - } -} diff --git a/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java b/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java index a752da3ce9c..58a702e4190 100644 --- a/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java +++ b/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java @@ -14,7 +14,10 @@ /** * A command that is only executable if a database is open. + * Deprecated use instead + * @see org.jabref.gui.actions.SimpleCommand */ +@Deprecated public class OldDatabaseCommandWrapper extends CommandBase { private static final Logger LOGGER = LoggerFactory.getLogger(OldDatabaseCommandWrapper.class); diff --git a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java index 7c13cbcc250..e6c0a29684c 100644 --- a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java +++ b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java @@ -2,17 +2,21 @@ import org.jabref.gui.JabRefFrame; import org.jabref.gui.preferences.PreferencesDialog; +import org.jabref.gui.util.TaskExecutor; public class ShowPreferencesAction extends SimpleCommand { private final JabRefFrame jabRefFrame; - public ShowPreferencesAction(JabRefFrame jabRefFrame) { + private final TaskExecutor taskExecutor; + + public ShowPreferencesAction(JabRefFrame jabRefFrame, TaskExecutor taskExecutor) { this.jabRefFrame = jabRefFrame; + this.taskExecutor = taskExecutor; } @Override public void execute() { - PreferencesDialog preferencesDialog = new PreferencesDialog(jabRefFrame); + PreferencesDialog preferencesDialog = new PreferencesDialog(jabRefFrame, taskExecutor); preferencesDialog.showAndWait(); } } diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index 69321ed5766..eb4c6508955 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -35,9 +35,6 @@ public enum StandardActions implements Action { OPEN_URL(Localization.lang("Open URL or DOI"), IconTheme.JabRefIcons.WWW, KeyBinding.OPEN_URL_OR_DOI), MERGE_WITH_FETCHED_ENTRY(Localization.lang("Get BibTeX data from %0", "DOI/ISBN/...")), ATTACH_FILE(Localization.lang("Attach file"), IconTheme.JabRefIcons.ATTACH_FILE), - ADD_TO_GROUP(Localization.lang("Add to group")), - REMOVE_FROM_GROUP(Localization.lang("Remove from group")), - MOVE_TO_GROUP(Localization.lang("Move to group")), PRIORITY(Localization.lang("Priority"), IconTheme.JabRefIcons.PRIORITY), CLEAR_PRIORITY(Localization.lang("Clear priority")), PRIORITY_HIGH(Localization.lang("Set priority to high"), IconTheme.JabRefIcons.PRIORITY_HIGH), @@ -47,11 +44,11 @@ public enum StandardActions implements Action { QUALITY_ASSURED(Localization.lang("Toggle quality assured"), IconTheme.JabRefIcons.QUALITY_ASSURED), RANKING(Localization.lang("Rank"), IconTheme.JabRefIcons.RANKING), CLEAR_RANK(Localization.lang("Clear rank")), - RANK_1("", IconTheme.JabRefIcons.RANK1), - RANK_2("", IconTheme.JabRefIcons.RANK2), - RANK_3("", IconTheme.JabRefIcons.RANK3), - RANK_4("", IconTheme.JabRefIcons.RANK4), - RANK_5("", IconTheme.JabRefIcons.RANK5), + RANK_1(Localization.lang("Set rank to one"), IconTheme.JabRefIcons.RANK1), + RANK_2(Localization.lang("Set rank to two"), IconTheme.JabRefIcons.RANK2), + RANK_3(Localization.lang("Set rank to three"), IconTheme.JabRefIcons.RANK3), + RANK_4(Localization.lang("Set rank to four"), IconTheme.JabRefIcons.RANK4), + RANK_5(Localization.lang("Set rank to five"), IconTheme.JabRefIcons.RANK5), PRINTED(Localization.lang("Printed"), IconTheme.JabRefIcons.PRINTED), TOGGLE_PRINTED(Localization.lang("Toggle print status"), IconTheme.JabRefIcons.PRINTED), READ_STATUS(Localization.lang("Read status"), IconTheme.JabRefIcons.READ_STATUS), @@ -60,10 +57,12 @@ public enum StandardActions implements Action { SKIMMED(Localization.lang("Set read status to skimmed"), IconTheme.JabRefIcons.READ_STATUS_SKIMMED), RELEVANCE(Localization.lang("Relevance"), IconTheme.JabRefIcons.RELEVANCE), RELEVANT(Localization.lang("Toggle relevance"), IconTheme.JabRefIcons.RELEVANCE), + NEW_LIBRARY(Localization.lang("New library"), IconTheme.JabRefIcons.NEW), NEW_LIBRARY_BIBTEX(Localization.lang("New %0 library", BibDatabaseMode.BIBTEX.getFormattedName()), IconTheme.JabRefIcons.NEW), NEW_LIBRARY_BIBLATEX(Localization.lang("New %0 library", BibDatabaseMode.BIBLATEX.getFormattedName()), IconTheme.JabRefIcons.NEW), OPEN_LIBRARY(Localization.lang("Open library"), IconTheme.JabRefIcons.OPEN, KeyBinding.OPEN_DATABASE), - IMPORT_EXPORT(Localization.lang("Import & Export"), IconTheme.JabRefIcons.IMPORT_EXPORT), + IMPORT(Localization.lang("Import"), IconTheme.JabRefIcons.IMPORT), + EXPORT(Localization.lang("Export"), IconTheme.JabRefIcons.EXPORT, KeyBinding.EXPORT), MERGE_DATABASE(Localization.lang("Append library"), Localization.lang("Append contents from a BibTeX library into the currently viewed library")), SAVE_LIBRARY(Localization.lang("Save library"), IconTheme.JabRefIcons.SAVE, KeyBinding.SAVE_DATABASE), SAVE_LIBRARY_AS(Localization.lang("Save library as..."), KeyBinding.SAVE_DATABASE_AS), @@ -71,19 +70,19 @@ public enum StandardActions implements Action { SAVE_ALL(Localization.lang("Save all"), Localization.lang("Save all open libraries"), IconTheme.JabRefIcons.SAVE_ALL, KeyBinding.SAVE_ALL), IMPORT_INTO_NEW_LIBRARY(Localization.lang("Import into new library"), KeyBinding.IMPORT_INTO_NEW_DATABASE), IMPORT_INTO_CURRENT_LIBRARY(Localization.lang("Import into current library"), KeyBinding.IMPORT_INTO_CURRENT_DATABASE), - EXPORT_ALL(Localization.lang("Export")), - EXPORT_SELECTED(Localization.lang("Export selected entries")), - CONNECT_TO_SHARED_DB(Localization.lang("Connect to shared database")), - PULL_CHANGES_FROM_SHARED_DB(Localization.lang("Pull changes from shared database"), IconTheme.JabRefIcons.PULL, KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), + EXPORT_ALL(Localization.lang("Export all entries")), + EXPORT_SELECTED(Localization.lang("Export selected entries"), KeyBinding.EXPORT_SELECTED), + CONNECT_TO_SHARED_DB(Localization.lang("Connect to shared database"), IconTheme.JabRefIcons.CONNECT_DB), + PULL_CHANGES_FROM_SHARED_DB(Localization.lang("Pull changes from shared database"), KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), CLOSE_LIBRARY(Localization.lang("Close library"), Localization.lang("Close the current library"), IconTheme.JabRefIcons.CLOSE, KeyBinding.CLOSE_DATABASE), QUIT(Localization.lang("Quit"), Localization.lang("Quit JabRef"), IconTheme.JabRefIcons.CLOSE_JABREF, KeyBinding.QUIT_JABREF), UNDO(Localization.lang("Undo"), IconTheme.JabRefIcons.UNDO, KeyBinding.UNDO), REDO(Localization.lang("Redo"), IconTheme.JabRefIcons.REDO, KeyBinding.REDO), - REPLACE_ALL(Localization.lang("Replace string"), KeyBinding.REPLACE_STRING), + REPLACE_ALL(Localization.lang("Find and replace"), KeyBinding.REPLACE_STRING), MANAGE_KEYWORDS(Localization.lang("Manage keywords")), - MASS_SET_FIELDS(Localization.lang("Set/clear/append/rename fields")), - TOGGLE_GROUPS(Localization.lang("Toggle groups interface"), IconTheme.JabRefIcons.TOGGLE_GROUPS, KeyBinding.TOGGLE_GROUPS_INTERFACE), - TOOGLE_OO(Localization.lang("OpenOffice/LibreOffice connection"), IconTheme.JabRefIcons.FILE_OPENOFFICE, KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION), + MASS_SET_FIELDS(Localization.lang("Manage field names & content")), + TOGGLE_GROUPS(Localization.lang("Groups interface"), IconTheme.JabRefIcons.TOGGLE_GROUPS, KeyBinding.TOGGLE_GROUPS_INTERFACE), + 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), 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), @@ -92,8 +91,10 @@ public enum StandardActions implements Action { OPEN_FILE(Localization.lang("Open file"), Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), OPEN_CONSOLE(Localization.lang("Open terminal here"), Localization.lang("Open terminal here"), IconTheme.JabRefIcons.CONSOLE, KeyBinding.OPEN_CONSOLE), COPY_LINKED_FILES(Localization.lang("Copy linked files to folder...")), - ABBREVIATE_ISO(Localization.lang("Abbreviate journal names (ISO)"), Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), - ABBREVIATE_MEDLINE(Localization.lang("Abbreviate journal names (MEDLINE)"), Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), + COPY_DOI(Localization.lang("Copy DOI url")), + ABBREVIATE(Localization.lang("Abbreviate journal names")), + ABBREVIATE_ISO("ISO", Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), + ABBREVIATE_MEDLINE("MEDLINE", Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), UNABBREVIATE(Localization.lang("Unabbreviate journal names"), Localization.lang("Unabbreviate journal names of the selected entries"), KeyBinding.UNABBREVIATE), MANAGE_CUSTOM_EXPORTS(Localization.lang("Manage custom exports")), @@ -109,11 +110,11 @@ public enum StandardActions implements Action { MANAGE_CONTENT_SELECTORS(Localization.lang("Manage content selectors"), IconTheme.JabRefIcons.PREFERENCES), MANAGE_CITE_KEY_PATTERNS(Localization.lang("BibTeX key patterns")), - TOGGLE_PREVIEW(Localization.lang("Toggle entry preview"), IconTheme.JabRefIcons.TOGGLE_ENTRY_PREVIEW, KeyBinding.TOGGLE_ENTRY_PREVIEW), - EDIT_ENTRY(Localization.lang("Edit entry"), IconTheme.JabRefIcons.EDIT_ENTRY, KeyBinding.EDIT_ENTRY), - SHOW_PDV_VIEWER(Localization.lang("Show document viewer"), IconTheme.JabRefIcons.PDF_FILE), - NEXT_PREVIEW_STYLE(Localization.lang("Next preview layout"), KeyBinding.NEXT_PREVIEW_LAYOUT), - PREVIOUS_PREVIEW_STYLE(Localization.lang("Previous preview layout"), KeyBinding.PREVIOUS_PREVIEW_LAYOUT), + 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), @@ -121,23 +122,27 @@ public enum StandardActions implements Action { 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")), - EDIT_STRINGS(Localization.lang("Edit strings"), IconTheme.JabRefIcons.EDIT_STRINGS, KeyBinding.EDIT_STRINGS), + EDIT_STRINGS(Localization.lang("Edit string constants"), IconTheme.JabRefIcons.EDIT_STRINGS, KeyBinding.EDIT_STRINGS), FIND_DUPLICATES(Localization.lang("Find duplicates"), IconTheme.JabRefIcons.FIND_DUPLICATES), MERGE_ENTRIES(Localization.lang("Merge entries"), IconTheme.JabRefIcons.MERGE_ENTRIES), RESOLVE_DUPLICATE_KEYS(Localization.lang("Resolve duplicate BibTeX keys"), Localization.lang("Find and remove duplicate BibTeX keys"), KeyBinding.RESOLVE_DUPLICATE_BIBTEX_KEYS), CHECK_INTEGRITY(Localization.lang("Check integrity"), KeyBinding.CHECK_INTEGRITY), - FIND_UNLINKED_FILES(Localization.lang("Find unlinked files"), Localization.lang("Searches for unlinked PDF files on the file system"), KeyBinding.FIND_UNLINKED_FILES), + FIND_UNLINKED_FILES(Localization.lang("Search for unlinked local files"), IconTheme.JabRefIcons.SEARCH, KeyBinding.FIND_UNLINKED_FILES), AUTO_LINK_FILES(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), - LOOKUP_DOC_IDENTIFIER(Localization.lang("Look up document identifier")), - LOOKUP_FULLTEXT(Localization.lang("Look up full text documents"), KeyBinding.DOWNLOAD_FULL_TEXT), + LOOKUP_DOC_IDENTIFIER(Localization.lang("Search document identifier online")), + LOOKUP_FULLTEXT(Localization.lang("Search full text documents online"), IconTheme.JabRefIcons.FILE_SEARCH, KeyBinding.DOWNLOAD_FULL_TEXT), GENERATE_CITE_KEY(Localization.lang("Generate BibTeX key"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - GENERATE_CITE_KEYS(Localization.lang("Autogenerate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - DOWNLOAD_FULL_TEXT(Localization.lang("Look up full text documents"), KeyBinding.DOWNLOAD_FULL_TEXT), + GENERATE_CITE_KEYS(Localization.lang("Generate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), + DOWNLOAD_FULL_TEXT(Localization.lang("Search full text documents online"), IconTheme.JabRefIcons.FILE_SEARCH, KeyBinding.DOWNLOAD_FULL_TEXT), CLEANUP_ENTRIES(Localization.lang("Cleanup entries"), IconTheme.JabRefIcons.CLEANUP_ENTRIES, KeyBinding.CLEANUP), - SET_FILE_LINKS(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), + SET_FILE_LINKS(Localization.lang("Automatically set file links"), KeyBinding.AUTOMATICALLY_LINK_FILES), HELP(Localization.lang("Online help"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_KEY_PATTERNS(Localization.lang("Help on key patterns"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_REGEX_SEARCH(Localization.lang("Help on regular expression search"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_NAME_FORMATTER(Localization.lang("Help on Name Formatting"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_SPECIAL_FIELDS(Localization.lang("Help on special fields"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), WEB_MENU(Localization.lang("JabRef resources")), OPEN_WEBPAGE(Localization.lang("Website"), Localization.lang("Opens JabRef's website")), OPEN_FACEBOOK("Facebook", Localization.lang("Opens JabRef's Facebook page"), IconTheme.JabRefIcons.FACEBOOK), diff --git a/src/main/java/org/jabref/gui/actions/WriteXMPAction.java b/src/main/java/org/jabref/gui/actions/WriteXMPAction.java index de4face8b53..67a1217a113 100644 --- a/src/main/java/org/jabref/gui/actions/WriteXMPAction.java +++ b/src/main/java/org/jabref/gui/actions/WriteXMPAction.java @@ -92,7 +92,7 @@ public void init() { } optionsDialog.open(); - basePanel.output(Localization.lang("Writing XMP-metadata...")); + dialogService.notify(Localization.lang("Writing XMP-metadata...")); } private void writeXMP() { @@ -162,7 +162,7 @@ private void writeXMP() { return; } - basePanel.output(Localization.lang("Finished writing XMP for %0 file (%1 skipped, %2 errors).", + dialogService.notify(Localization.lang("Finished writing XMP for %0 file (%1 skipped, %2 errors).", String.valueOf(entriesChanged), String.valueOf(skipped), String.valueOf(errors))); } diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java index 647c54a1fc0..3246ff21267 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java @@ -5,6 +5,7 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.util.BaseDialog; +import org.jabref.logic.l10n.Localization; import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; import org.jabref.model.metadata.MetaData; @@ -25,6 +26,8 @@ public BibtexKeyPatternDialog(BasePanel panel) { private void init() { + this.setTitle(Localization.lang("BibTeX key patterns")); + this.getDialogPane().setContent(bibtexKeyPatternPanel.getPanel()); this.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.CANCEL); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index 994452e5efa..e1e81d2bc03 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -1,7 +1,5 @@ package org.jabref.gui.bibtexkeypattern; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -15,6 +13,8 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.StandardActions; import org.jabref.gui.help.HelpAction; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; @@ -28,15 +28,8 @@ public class BibtexKeyPatternPanel extends Pane { - // used by both BibtexKeyPatternPanel and TabLabelPAttern - protected final GridBagLayout gbl = new GridBagLayout(); - protected final GridBagConstraints con = new GridBagConstraints(); - // default pattern protected final TextField defaultPat = new TextField(); - private final HelpAction help; - - private final int COLUMNS = 2; // one field for each type private final Map textFields = new HashMap<>(); @@ -45,7 +38,6 @@ public class BibtexKeyPatternPanel extends Pane { public BibtexKeyPatternPanel(BasePanel panel) { this.panel = panel; - help = new HelpAction(Localization.lang("Help on key patterns"), HelpFile.BIBTEX_KEY_PATTERN); gridPane.setHgap(10); gridPane.setVgap(5); buildGUI(); @@ -64,7 +56,8 @@ private void buildGUI() { int rowIndex = 1; int columnIndex = 0; // The header - can be removed - for (int i = 0; i < COLUMNS; i++) { + int columnsNumber = 2; + for (int i = 0; i < columnsNumber; i++) { Label label = new Label(Localization.lang("Entry type")); Label keyPattern = new Label(Localization.lang("Key pattern")); gridPane.add(label, ++columnIndex, rowIndex); @@ -93,7 +86,7 @@ private void buildGUI() { textFields.put(type.getName().toLowerCase(Locale.ROOT), textField); - if (columnIndex == COLUMNS - 1) { + if (columnIndex == (columnsNumber - 1)) { columnIndex = 0; rowIndex++; } else { @@ -103,9 +96,9 @@ private void buildGUI() { rowIndex++; - Button help1 = new Button("?"); - help1.setOnAction(e -> new HelpAction(Localization.lang("Help on key patterns"), HelpFile.BIBTEX_KEY_PATTERN).getHelpButton().doClick()); - gridPane.add(help1, 1, rowIndex); + ActionFactory factory = new ActionFactory(Globals.prefs.getKeyBindingRepository()); + Button help = factory.createIconButton(StandardActions.HELP_KEY_PATTERNS, new HelpAction(HelpFile.BIBTEX_KEY_PATTERN)); + gridPane.add(help, 1, rowIndex); Button btnDefaultAll1 = new Button(Localization.lang("Reset all")); btnDefaultAll1.setOnAction(e -> { @@ -118,7 +111,6 @@ private void buildGUI() { gridPane.add(btnDefaultAll1, 2, rowIndex); } - /** * fill the given LabelPattern by values generated from the text fields */ @@ -139,9 +131,7 @@ private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { } protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() { - GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern( - JabRefPreferences.getInstance().get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN) - ); + GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern(Globals.prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); fillPatternUsingPanelData(res); return res; } @@ -162,7 +152,7 @@ public void setValues(AbstractBibtexKeyPattern keyPattern) { setValue(entry.getValue(), entry.getKey(), keyPattern); } - if (keyPattern.getDefaultValue() == null || keyPattern.getDefaultValue().isEmpty()) { + if ((keyPattern.getDefaultValue() == null) || keyPattern.getDefaultValue().isEmpty()) { defaultPat.setText(""); } else { defaultPat.setText(keyPattern.getDefaultValue().get(0)); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java b/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java deleted file mode 100644 index 68006125528..00000000000 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java +++ /dev/null @@ -1,138 +0,0 @@ -package org.jabref.gui.bibtexkeypattern; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; - -import javafx.embed.swing.JFXPanel; -import javafx.scene.Scene; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.FXDialogService; -import org.jabref.gui.PreviewPanel; -import org.jabref.gui.customjfx.CustomJFXPanel; -import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; - -import com.jgoodies.forms.builder.ButtonBarBuilder; -import com.jgoodies.forms.builder.FormBuilder; -import com.jgoodies.forms.layout.FormLayout; - -/** - * Dialog box for resolving duplicate bibte keys - */ -class ResolveDuplicateLabelDialog { - - private final JDialog diag; - private final List cbs = new ArrayList<>(); - private boolean okPressed; - private boolean cancelPressed; - - public ResolveDuplicateLabelDialog(BasePanel panel, String key, List entries) { - diag = new JDialog((JFrame) null, Localization.lang("Duplicate BibTeX key"), true); - - FormBuilder b = FormBuilder.create().layout(new FormLayout( - "left:pref, 4dlu, fill:pref", "p")); - b.add(new JLabel(Localization.lang("Duplicate BibTeX key") + ": " + key)).xyw(1, 1, 3); - b.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - boolean first = true; - int row = 3; - for (BibEntry entry : entries) { - JCheckBox cb = new JCheckBox(Localization.lang("Generate BibTeX key"), !first); - b.appendRows("1dlu, p"); - b.add(cb).xy(1, row); - PreviewPanel previewPanel = new PreviewPanel(null, panel.getBibDatabaseContext(), Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService(), ExternalFileTypes.getInstance()); - previewPanel.setEntry(entry); - JFXPanel container = CustomJFXPanel.wrap(new Scene(previewPanel)); - container.setPreferredSize(new Dimension(800, 90)); - b.add(container).xy(3, row); - row += 2; - cbs.add(cb); - first = false; - } - - ButtonBarBuilder bb = new ButtonBarBuilder(); - bb.addGlue(); - JButton ok = new JButton(Localization.lang("OK")); - bb.addButton(ok); - JButton ignore = new JButton(Localization.lang("Ignore")); - bb.addButton(ignore); - JButton cancel = new JButton(Localization.lang("Cancel")); - bb.addButton(cancel); - bb.addGlue(); - bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - diag.getContentPane().add(b.getPanel(), BorderLayout.CENTER); - diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); - - diag.pack(); - - ok.addActionListener(e -> { - okPressed = true; - diag.dispose(); - }); - - ignore.addActionListener(e -> diag.dispose()); - - AbstractAction closeAction = new AbstractAction() { - - @Override - public void actionPerformed(ActionEvent e) { - cancelPressed = true; - diag.dispose(); - } - }; - - cancel.addActionListener(closeAction); - - ActionMap am = b.getPanel().getActionMap(); - InputMap im = b.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", closeAction); - } - - /** - * After the dialog has been closed, this query answers whether the dialog was okPressed - * (by cancel button or by closing the dialog directly). - * @return true if it was okPressed, false if Ok was pressed. - */ - public boolean isOkPressed() { - return okPressed; - } - - /** - * Get the list of checkboxes where the user has selected which entries to generate - * new keys for. - * @return the list of checkboxes - */ - public List getCheckBoxes() { - return cbs; - } - - public void show() { - okPressed = false; - diag.setLocationRelativeTo(diag.getParent()); - diag.setVisible(true); - } - - public boolean isCancelPressed() { - return cancelPressed; - } -} diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java b/src/main/java/org/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java deleted file mode 100644 index 297d42a64c5..00000000000 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.jabref.gui.bibtexkeypattern; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import javax.swing.JCheckBox; -import javax.swing.SwingUtilities; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.actions.BaseAction; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableKeyChange; -import org.jabref.gui.util.BackgroundTask; -import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.FieldChange; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; - -/** - * Function for resolving duplicate BibTeX keys. - */ -public class SearchFixDuplicateLabels implements BaseAction { - - private final BasePanel panel; - - public SearchFixDuplicateLabels(BasePanel panel) { - this.panel = panel; - } - - @Override - public void action() throws Exception { - panel.output(Localization.lang("Resolving duplicate BibTeX keys...")); - BackgroundTask.wrap(this::findDuplicates) - .onSuccess(dupes -> SwingUtilities.invokeLater(() -> resolveDuplicates(dupes))) - .executeWith(Globals.TASK_EXECUTOR); - } - - private void resolveDuplicates(Map> dupes) { - List toGenerateFor = new ArrayList<>(); - for (Map.Entry> dupeEntry : dupes.entrySet()) { - ResolveDuplicateLabelDialog rdld = new ResolveDuplicateLabelDialog(panel, dupeEntry.getKey(), dupeEntry.getValue()); - rdld.show(); - if (rdld.isOkPressed()) { - List cbs = rdld.getCheckBoxes(); - for (int i = 0; i < cbs.size(); i++) { - if (cbs.get(i).isSelected()) { - // The checkbox for entry i has been selected, so we should generate a new key for it: - toGenerateFor.add(dupeEntry.getValue().get(i)); - } - } - } else if (rdld.isCancelPressed()) { - break; - } - } - - // Do the actual generation: - if (!toGenerateFor.isEmpty()) { - NamedCompound ce = new NamedCompound(Localization.lang("Resolve duplicate BibTeX keys")); - BibtexKeyGenerator keyGenerator = new BibtexKeyGenerator(panel.getBibDatabaseContext(), Globals.prefs.getBibtexKeyPatternPreferences()); - for (BibEntry entry : toGenerateFor) { - Optional change = keyGenerator.generateAndSetKey(entry); - change.ifPresent(fieldChange -> ce.addEdit(new UndoableKeyChange(fieldChange))); - } - ce.end(); - panel.getUndoManager().addEdit(ce); - panel.markBaseChanged(); - } - panel.output(Localization.lang("Finished resolving duplicate BibTeX keys. %0 entries modified.", - String.valueOf(toGenerateFor.size()))); - } - - private Map> findDuplicates() { - // Find all multiple occurrences of BibTeX keys. - Map> dupes = new HashMap<>(); - - Map foundKeys = new HashMap<>(); - BibDatabase db = panel.getDatabase(); - for (BibEntry entry : db.getEntries()) { - entry.getCiteKeyOptional().filter(key -> !key.isEmpty()).ifPresent(key -> { - // See whether this entry's key is already known: - if (foundKeys.containsKey(key)) { - // Already known, so we have found a dupe. See if it was already found as a dupe: - if (dupes.containsKey(key)) { - // Already in the dupe map. Add this entry as well: - dupes.get(key).add(entry); - } else { - // Construct a list of entries for this key: - List al = new ArrayList<>(); - // Add both the first one we found, and the one we found just now: - al.add(foundKeys.get(key)); - al.add(entry); - // Add the list to the dupe map: - dupes.put(key, al); - } - } else { - // Not already known. Add key and entry to map: - foundKeys.put(key, entry); - } - }); - } - return dupes; - } -} diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupActionsListModel.java b/src/main/java/org/jabref/gui/cleanup/CleanupActionsListModel.java deleted file mode 100644 index f7bf8a5e463..00000000000 --- a/src/main/java/org/jabref/gui/cleanup/CleanupActionsListModel.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.jabref.gui.cleanup; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.swing.ListModel; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; - -import org.jabref.model.cleanup.FieldFormatterCleanup; -import org.jabref.model.cleanup.FieldFormatterCleanups; - -public class CleanupActionsListModel implements ListModel { - - private List cleanupActions; - private final List listeners = new ArrayList<>(); - - - public CleanupActionsListModel(List cleanupAction) { - Objects.requireNonNull(cleanupAction); - this.cleanupActions = cleanupAction; - - } - - public void addCleanupAction(FieldFormatterCleanup action) { - if (!cleanupActions.contains(action)) { - cleanupActions.add(action); - for (ListDataListener listener : listeners) { - listener.intervalAdded(new ListDataEvent(action, ListDataEvent.INTERVAL_ADDED, cleanupActions.size(), - cleanupActions.size())); - } - } - } - - /** - * Removes the action at the specified index from the list. - * Removal is only done when index {@code >=0} and index {@code<=} list size - * @param index The index to remove - */ - public void removeAtIndex(int index) { - - if ((index >= 0) && (index < cleanupActions.size())) { - FieldFormatterCleanup action = cleanupActions.remove(index); - for (ListDataListener listener : listeners) { - listener.intervalRemoved(new ListDataEvent(action, ListDataEvent.INTERVAL_REMOVED, index, index)); - } - } - } - - public List getAllActions() { - return cleanupActions; - } - - @Override - public int getSize() { - return cleanupActions.size(); - } - - @Override - public FieldFormatterCleanup getElementAt(int index) { - return cleanupActions.get(index); - } - - @Override - public void addListDataListener(ListDataListener l) { - listeners.add(l); - } - - @Override - public void removeListDataListener(ListDataListener l) { - listeners.remove(l); - } - - public void reset(FieldFormatterCleanups defaultFormatters) { - cleanupActions = new ArrayList<>(defaultFormatters.getConfiguredActions()); - for (ListDataListener listener : listeners) { - listener.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, cleanupActions.size())); - } - } -} diff --git a/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java b/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java index f622bd844ac..1a522953e24 100644 --- a/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java +++ b/src/main/java/org/jabref/gui/collab/ChangeDisplayDialog.java @@ -1,148 +1,81 @@ package org.jabref.gui.collab; -import java.awt.BorderLayout; -import java.awt.Insets; -import java.util.Collections; -import java.util.Enumeration; +import java.util.List; + +import javafx.collections.FXCollections; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.BorderPane; -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTree; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreeNode; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefDialog; import org.jabref.gui.undo.NamedCompound; +import org.jabref.gui.util.BaseDialog; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; - -class ChangeDisplayDialog extends JabRefDialog implements TreeSelectionListener { - - private final JTree tree; - private final JPanel infoPanel = new JPanel(); - private final JCheckBox cb = new JCheckBox(Localization.lang("Accept change")); - private final JLabel rootInfo = new JLabel(Localization.lang("Select the tree nodes to view and accept or reject changes") + '.'); - private ChangeViewModel selected; - private JComponent infoShown; - private boolean okPressed; - - public ChangeDisplayDialog(final BasePanel panel, - BibDatabase secondary, final DefaultMutableTreeNode root) { - super(Localization.lang("External changes"), true, ChangeDisplayDialog.class); - BibDatabase localSecondary; - - // Just to be sure, put in an empty secondary base if none is given: - if (secondary == null) { - localSecondary = new BibDatabase(); - } else { - localSecondary = secondary; - } - tree = new JTree(root); - tree.addTreeSelectionListener(this); - - JSplitPane pane = new JSplitPane(); - pane.setLeftComponent(new JScrollPane(tree)); - JPanel infoBorder = new JPanel(); - pane.setRightComponent(infoBorder); - - cb.setMargin(new Insets(2, 2, 2, 2)); - cb.setEnabled(false); - infoPanel.setLayout(new BorderLayout()); - infoBorder.setLayout(new BorderLayout()); - infoBorder.setBorder(BorderFactory.createEtchedBorder()); - infoBorder.add(infoPanel, BorderLayout.CENTER); - setInfo(rootInfo); - infoPanel.add(cb, BorderLayout.SOUTH); - - JButton ok = new JButton(Localization.lang("OK")); - JPanel buttonPanel = new JPanel(); - buttonPanel.add(ok); - JButton cancel = new JButton(Localization.lang("Cancel")); - buttonPanel.add(cancel); - - getContentPane().add(pane, BorderLayout.CENTER); - getContentPane().add(buttonPanel, BorderLayout.SOUTH); +import org.jabref.model.database.BibDatabaseContext; + +import org.fxmisc.easybind.EasyBind; + +class ChangeDisplayDialog extends BaseDialog { + + private final ListView tree; + private final BorderPane infoPanel = new BorderPane(); + private final CheckBox cb = new CheckBox(Localization.lang("Accept change")); + + public ChangeDisplayDialog(BibDatabaseContext database, List changes) { + this.setTitle(Localization.lang("External changes")); + this.getDialogPane().setPrefSize(800, 600); + + tree = new ListView<>(FXCollections.observableArrayList(changes)); + tree.setPrefWidth(190); + EasyBind.subscribe(tree.getSelectionModel().selectedItemProperty(), this::selectedChangeChanged); + + SplitPane pane = new SplitPane(); + pane.setDividerPositions(0.25); + pane.getItems().addAll(new ScrollPane(tree), infoPanel); + getDialogPane().setContent(pane); + + infoPanel.setBottom(cb); + Label rootInfo = new Label(Localization.lang("Select the tree nodes to view and accept or reject changes") + '.'); + infoPanel.setCenter(rootInfo); + + getDialogPane().getButtonTypes().setAll( + new ButtonType(Localization.lang("Accept changes"), ButtonBar.ButtonData.APPLY), + ButtonType.CANCEL + ); + + setResultConverter(button -> { + if (button == ButtonType.CANCEL) { + return false; + } else { + // Perform all accepted changes + NamedCompound ce = new NamedCompound(Localization.lang("Merged external changes")); + for (DatabaseChangeViewModel change : changes) { + if (change.isAccepted()) { + change.makeChange(database, ce); + } + } + ce.end(); + //TODO: panel.getUndoManager().addEdit(ce); - cb.addChangeListener(e -> { - if (selected != null) { - selected.setAccepted(cb.isSelected()); + return true; } }); - cancel.addActionListener(e -> dispose()); - - ok.addActionListener(e -> { - - // Perform all accepted changes: - // Store all edits in an Undoable object: - NamedCompound ce = new NamedCompound(Localization.lang("Merged external changes")); - // TODO: Java 9: Generics are stricter? - Enumeration enumer = root.children(); - boolean anyDisabled = false; - for (TreeNode c : Collections.list(enumer)) { - ChangeViewModel model = (ChangeViewModel) c; - boolean allAccepted = false; - if (model.isAcceptable() && model.isAccepted()) { - allAccepted = model.makeChange(panel, localSecondary, ce); - } - - if (!allAccepted) { - anyDisabled = true; - } - } - ce.end(); - panel.getUndoManager().addEdit(ce); - if (anyDisabled) { - panel.markBaseChanged(); + EasyBind.subscribe(cb.selectedProperty(), selected -> { + if (selected != null && tree.getSelectionModel().getSelectedItem() != null) { + tree.getSelectionModel().getSelectedItem().setAccepted(selected); } - panel.markExternalChangesAsResolved(); - dispose(); - okPressed = true; }); - - pack(); - } - - public boolean isOkPressed() { - return okPressed; - } - - private void setInfo(JComponent comp) { - if (infoShown != null) { - infoPanel.remove(infoShown); - } - infoShown = comp; - infoPanel.add(infoShown, BorderLayout.CENTER); - infoPanel.revalidate(); - infoPanel.repaint(); } - /** - * valueChanged - * - * @param e TreeSelectionEvent - */ - @Override - public void valueChanged(TreeSelectionEvent e) { - Object o = tree.getLastSelectedPathComponent(); - if (o instanceof ChangeViewModel) { - selected = (ChangeViewModel) o; - setInfo(selected.description()); - cb.setSelected(selected.isAccepted()); - cb.setEnabled(selected.isAcceptable()); - } else { - setInfo(rootInfo); - selected = null; - cb.setEnabled(false); + private void selectedChangeChanged(DatabaseChangeViewModel currentChange) { + if (currentChange != null) { + infoPanel.setCenter(currentChange.description()); + cb.setSelected(currentChange.isAccepted()); } } } diff --git a/src/main/java/org/jabref/gui/collab/ChangeScanner.java b/src/main/java/org/jabref/gui/collab/ChangeScanner.java index 7fb1b74e388..021a941c87f 100644 --- a/src/main/java/org/jabref/gui/collab/ChangeScanner.java +++ b/src/main/java/org/jabref/gui/collab/ChangeScanner.java @@ -1,68 +1,33 @@ package org.jabref.gui.collab; -import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Optional; -import javax.swing.SwingUtilities; -import javax.swing.tree.DefaultMutableTreeNode; - import org.jabref.Globals; -import org.jabref.JabRefExecutorService; -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefFrame; import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.bibtex.comparator.BibDatabaseDiff; import org.jabref.logic.bibtex.comparator.BibEntryDiff; import org.jabref.logic.bibtex.comparator.BibStringDiff; -import org.jabref.logic.exporter.AtomicFileWriter; -import org.jabref.logic.exporter.BibDatabaseWriter; -import org.jabref.logic.exporter.BibtexDatabaseWriter; -import org.jabref.logic.exporter.SavePreferences; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.OpenDatabase; import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ChangeScanner implements Runnable { - - private static final Logger LOGGER = LoggerFactory.getLogger(ChangeScanner.class); +public class ChangeScanner { - private final Optional file; - private final Path tempFile; - private final BibDatabaseContext databaseInMemory; + private final Path referenceFile; + private final BibDatabaseContext database; + private final List changes = new ArrayList<>(); + private BibDatabaseContext referenceDatabase; - private final BasePanel panel; - private final JabRefFrame frame; - private BibDatabaseContext databaseInTemp; - - /** - * We create an ArrayList to hold the changes we find. These will be added in the form - * of UndoEdit objects. We instantiate these so that the changes found in the file on disk - * can be reproduced in memory by calling redo() on them. REDO, not UNDO! - */ - private final DefaultMutableTreeNode changes = new DefaultMutableTreeNode(Localization.lang("External changes")); - - // NamedCompound edit = new NamedCompound("Merged external changes") - - public ChangeScanner(JabRefFrame frame, BasePanel bp, Path file, Path tempFile) { - this.panel = bp; - this.frame = frame; - this.databaseInMemory = bp.getBibDatabaseContext(); - this.file = Optional.ofNullable(file); - this.tempFile = tempFile; - } - - public boolean changesFound() { - return changes.getChildCount() > 0; + public ChangeScanner(BibDatabaseContext database, Path referenceFile) { + this.database = database; + this.referenceFile = referenceFile; } /** @@ -75,101 +40,58 @@ private static BibEntry bestFit(BibEntry targetEntry, List entries) { .orElse(null); } - public void displayResult(final DisplayResultCallback fup) { - if (changes.getChildCount() > 0) { - SwingUtilities.invokeLater(() -> { - ChangeDisplayDialog changeDialog = new ChangeDisplayDialog(panel, databaseInTemp.getDatabase(), changes); - changeDialog.setVisible(true); - fup.scanResultsResolved(changeDialog.isOkPressed()); - if (changeDialog.isOkPressed()) { - // Overwrite the temp database: - storeTempDatabase(); - } - }); - } else { - frame.getDialogService().showInformationDialogAndWait(Localization.lang("External changes"), - Localization.lang("No actual changes found.")); - - fup.scanResultsResolved(true); - } - } - - private void storeTempDatabase() { - JabRefExecutorService.INSTANCE.execute(() -> { - try { - SavePreferences prefs = Globals.prefs.loadForSaveFromPreferences() - .withMakeBackup(false) - .withEncoding(panel.getBibDatabaseContext() - .getMetaData() - .getEncoding() - .orElse(Globals.prefs.getDefaultEncoding())); - - BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(new AtomicFileWriter(tempFile, prefs.getEncoding()), prefs); - databaseWriter.saveDatabase(databaseInTemp); - } catch (IOException ex) { - LOGGER.warn("Problem updating tmp file after accepting external changes", ex); - } - }); - } - - @Override - public void run() { - file.ifPresent(diskdb -> { + public List scanForChanges() { + database.getDatabasePath().ifPresent(diskdb -> { // Parse the temporary file. ImportFormatPreferences importFormatPreferences = Globals.prefs.getImportFormatPreferences(); - ParserResult result = OpenDatabase.loadDatabase(tempFile.toAbsolutePath().toString(), importFormatPreferences, Globals.getFileUpdateMonitor()); - databaseInTemp = result.getDatabaseContext(); + ParserResult result = OpenDatabase.loadDatabase(referenceFile.toAbsolutePath().toString(), importFormatPreferences, Globals.getFileUpdateMonitor()); + referenceDatabase = result.getDatabaseContext(); // Parse the modified file. result = OpenDatabase.loadDatabase(diskdb.toAbsolutePath().toString(), importFormatPreferences, Globals.getFileUpdateMonitor()); BibDatabaseContext databaseOnDisk = result.getDatabaseContext(); // Start looking at changes. - BibDatabaseDiff differences = BibDatabaseDiff.compare(databaseInTemp, databaseOnDisk); + BibDatabaseDiff differences = BibDatabaseDiff.compare(referenceDatabase, databaseOnDisk); differences.getMetaDataDifferences().ifPresent(diff -> { changes.add(new MetaDataChangeViewModel(diff)); diff.getGroupDifferences().ifPresent(groupDiff -> changes.add(new GroupChangeViewModel(groupDiff))); }); - differences.getPreambleDifferences().ifPresent(diff -> changes.add(new PreambleChangeViewModel(databaseInMemory.getDatabase().getPreamble().orElse(""), diff))); + differences.getPreambleDifferences().ifPresent(diff -> changes.add(new PreambleChangeViewModel(diff))); differences.getBibStringDifferences().forEach(diff -> changes.add(createBibStringDiff(diff))); differences.getEntryDifferences().forEach(diff -> changes.add(createBibEntryDiff(diff))); }); + return changes; } - private ChangeViewModel createBibStringDiff(BibStringDiff diff) { + private DatabaseChangeViewModel createBibStringDiff(BibStringDiff diff) { if (diff.getOriginalString() == null) { return new StringAddChangeViewModel(diff.getNewString()); } if (diff.getNewString() == null) { - Optional current = databaseInMemory.getDatabase().getStringByName(diff.getOriginalString().getName()); + Optional current = database.getDatabase().getStringByName(diff.getOriginalString().getName()); return new StringRemoveChangeViewModel(diff.getOriginalString(), current.orElse(null)); } if (diff.getOriginalString().getName().equals(diff.getNewString().getName())) { - Optional current = databaseInMemory.getDatabase().getStringByName(diff.getOriginalString().getName()); + Optional current = database.getDatabase().getStringByName(diff.getOriginalString().getName()); return new StringChangeViewModel(current.orElse(null), diff.getOriginalString(), diff.getNewString().getContent()); } - Optional current = databaseInMemory.getDatabase().getStringByName(diff.getOriginalString().getName()); + Optional current = database.getDatabase().getStringByName(diff.getOriginalString().getName()); return new StringNameChangeViewModel(current.orElse(null), diff.getOriginalString(), current.map(BibtexString::getName).orElse(""), diff.getNewString().getName()); } - private ChangeViewModel createBibEntryDiff(BibEntryDiff diff) { + private DatabaseChangeViewModel createBibEntryDiff(BibEntryDiff diff) { if (diff.getOriginalEntry() == null) { return new EntryAddChangeViewModel(diff.getNewEntry()); } if (diff.getNewEntry() == null) { - return new EntryDeleteChangeViewModel(bestFit(diff.getOriginalEntry(), databaseInMemory.getEntries()), diff.getOriginalEntry()); + return new EntryDeleteChangeViewModel(bestFit(diff.getOriginalEntry(), database.getEntries()), diff.getOriginalEntry()); } - return new EntryChangeViewModel(bestFit(diff.getOriginalEntry(), databaseInMemory.getEntries()), diff.getOriginalEntry(), diff.getNewEntry()); - } - - @FunctionalInterface - public interface DisplayResultCallback { - - void scanResultsResolved(boolean resolved); + return new EntryChangeViewModel(bestFit(diff.getOriginalEntry(), database.getEntries()), diff.getOriginalEntry(), diff.getNewEntry()); } } diff --git a/src/main/java/org/jabref/gui/collab/ChangeViewModel.java b/src/main/java/org/jabref/gui/collab/ChangeViewModel.java deleted file mode 100644 index 0561a799b24..00000000000 --- a/src/main/java/org/jabref/gui/collab/ChangeViewModel.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.jabref.gui.collab; - -import javax.swing.JComponent; -import javax.swing.tree.DefaultMutableTreeNode; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.model.database.BibDatabase; - -abstract class ChangeViewModel extends DefaultMutableTreeNode { - - protected String name; - private boolean accepted = true; - - - ChangeViewModel() { - name = ""; - } - - ChangeViewModel(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - - public boolean isAccepted() { - return accepted; - } - - public void setAccepted(boolean a) { - accepted = a; - } - - /** - * This method is used to disable the "accept" box if the parent has been set to "not accepted". - * Thus the user can disable e.g. an entry change without having to disable all field changes. - * @return boolean false if the parent overrides by not being accepted. - */ - public boolean isAcceptable() { - if ((getParent() != null) && (getParent() instanceof ChangeViewModel)) { - return ((ChangeViewModel) getParent()).isAccepted(); - } else { - return true; - } - } - - /** - * This method returns a JComponent detailing the nature of the change. - * @return JComponent - */ - public abstract JComponent description(); - - /** - * Perform the change. This method is responsible for adding a proper undo edit to - * the NamedCompound, so the change can be undone. - * @param panel BasePanel The tab where the database lives. - * @param secondary BibDatabase The "tmp" database for which the change - * should also be made. - * @param undoEdit NamedCompound The compound to hold the undo edits. - * @return true if all changes were made, false if not all were accepted. - */ - public abstract boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit); - -} diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangeListener.java b/src/main/java/org/jabref/gui/collab/DatabaseChangeListener.java new file mode 100644 index 00000000000..cfb9ac2e1ff --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangeListener.java @@ -0,0 +1,7 @@ +package org.jabref.gui.collab; + +import java.util.List; + +public interface DatabaseChangeListener { + void databaseChanged(List changes); +} diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java index 701679fed5f..2bf20a9b69d 100644 --- a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java @@ -3,14 +3,11 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Optional; +import java.util.ArrayList; +import java.util.List; -import javax.swing.SwingUtilities; - -import org.jabref.JabRefExecutorService; -import org.jabref.gui.BasePanel; -import org.jabref.gui.SidePaneManager; -import org.jabref.gui.SidePaneType; +import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.util.FileUpdateListener; @@ -24,25 +21,22 @@ public class DatabaseChangeMonitor implements FileUpdateListener { private final BibDatabaseContext database; private final FileUpdateMonitor fileMonitor; - private final BasePanel panel; - private boolean updatedExternally; - private Path tmpFile; - private long timeStamp; - private long fileSize; + private final List listeners; + private Path referenceFile; + private TaskExecutor taskExecutor; - public DatabaseChangeMonitor(BibDatabaseContext database, FileUpdateMonitor fileMonitor, BasePanel panel) { + public DatabaseChangeMonitor(BibDatabaseContext database, FileUpdateMonitor fileMonitor, TaskExecutor taskExecutor) { this.database = database; this.fileMonitor = fileMonitor; - this.panel = panel; + this.taskExecutor = taskExecutor; + this.listeners = new ArrayList<>(); this.database.getDatabasePath().ifPresent(path -> { try { fileMonitor.addListenerForFile(path, this); - timeStamp = Files.getLastModifiedTime(path).toMillis(); - fileSize = Files.size(path); - tmpFile = Files.createTempFile("jabref", ".bib"); - tmpFile.toFile().deleteOnExit(); - copyToTemp(path); + referenceFile = Files.createTempFile("jabref", ".bib"); + referenceFile.toFile().deleteOnExit(); + setAsReference(path); } catch (IOException e) { LOGGER.error("Error while trying to monitor " + path, e); } @@ -51,93 +45,34 @@ public DatabaseChangeMonitor(BibDatabaseContext database, FileUpdateMonitor file @Override public void fileUpdated() { - if (panel.isSaving()) { - // We are just saving the file, so this message is most likely due to bad timing. - // If not, we'll handle it on the next polling. - return; - } - - updatedExternally = true; - - final ChangeScanner scanner = new ChangeScanner(panel.frame(), panel, database.getDatabasePath().orElse(null), tmpFile); - JabRefExecutorService.INSTANCE.executeInterruptableTaskAndWait(scanner); - - // Adding the sidepane component is Swing work, so we must do this in the Swing - // thread: - Runnable t = () -> { - - // Check if there is already a notification about external changes: - SidePaneManager sidePaneManager = panel.getSidePaneManager(); - boolean hasAlready = sidePaneManager.isComponentVisible(SidePaneType.FILE_UPDATE_NOTIFICATION); - if (hasAlready) { - sidePaneManager.hide(SidePaneType.FILE_UPDATE_NOTIFICATION); - } - - FileUpdatePanel component = (FileUpdatePanel) sidePaneManager.getComponent(SidePaneType.FILE_UPDATE_NOTIFICATION); - component.showForFile(panel, database.getDatabaseFile().orElse(null), scanner); - }; - - if (scanner.changesFound()) { - SwingUtilities.invokeLater(t); - } else { - updatedExternally = false; - } + // File on disk has changed, thus look for notable changes and notify listeners in case there are such changes + ChangeScanner scanner = new ChangeScanner(database, referenceFile); + BackgroundTask.wrap(scanner::scanForChanges) + .onSuccess(changes -> { + if (!changes.isEmpty()) { + listeners.forEach(listener -> listener.databaseChanged(changes)); + } + }) + .executeWith(taskExecutor); } - /** - * Forces a check on the file, and returns the result. Check if time stamp or the file size has changed. - * - * @return boolean true if the file has changed. - */ - private boolean hasBeenModified() { - Optional file = database.getDatabasePath(); - if (file.isPresent()) { - try { - long modified = Files.getLastModifiedTime(file.get()).toMillis(); - if (modified == 0L) { - // File deleted - return false; - } - long fileSizeNow = Files.size(file.get()); - return (timeStamp != modified) || (fileSize != fileSizeNow); - } catch (IOException ex) { - return false; - } - } - return false; + public void addListener(DatabaseChangeListener listener) { + listeners.add(listener); } public void unregister() { database.getDatabasePath().ifPresent(file -> fileMonitor.removeListener(file, this)); } - public boolean hasBeenModifiedExternally() { - return updatedExternally || hasBeenModified(); - } - public void markExternalChangesAsResolved() { - updatedExternally = false; markAsSaved(); } public void markAsSaved() { - database.getDatabasePath().ifPresent(file -> { - try { - timeStamp = Files.getLastModifiedTime(file).toMillis(); - fileSize = Files.size(file); - - copyToTemp(file); - } catch (IOException ex) { - LOGGER.error("Error while getting file information", ex); - } - }); - } - - private void copyToTemp(Path file) { - FileUtil.copyFile(file, tmpFile, true); + database.getDatabasePath().ifPresent(this::setAsReference); } - public Path getTempFile() { - return tmpFile; + private void setAsReference(Path file) { + FileUtil.copyFile(file, referenceFile, true); } } diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangePane.java b/src/main/java/org/jabref/gui/collab/DatabaseChangePane.java new file mode 100644 index 00000000000..17582a41ba9 --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangePane.java @@ -0,0 +1,46 @@ +package org.jabref.gui.collab; + +import java.util.List; + +import javafx.scene.Node; + +import org.jabref.gui.icon.IconTheme; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; + +import org.controlsfx.control.NotificationPane; +import org.controlsfx.control.action.Action; + +public class DatabaseChangePane extends NotificationPane { + + private final DatabaseChangeMonitor monitor; + private final BibDatabaseContext database; + + public DatabaseChangePane(Node parent, BibDatabaseContext database, DatabaseChangeMonitor monitor) { + super(parent); + this.database = database; + this.monitor = monitor; + + this.setGraphic(IconTheme.JabRefIcons.SAVE.getGraphicNode()); + this.setText(Localization.lang("The library has been modified by another program.")); + + monitor.addListener(this::onDatabaseChanged); + } + + private void onDatabaseChanged(List changes) { + this.getActions().setAll( + new Action(Localization.lang("Dismiss changes"), event -> { + monitor.markExternalChangesAsResolved(); + this.hide(); + }), + new Action(Localization.lang("Review changes"), event -> { + ChangeDisplayDialog changeDialog = new ChangeDisplayDialog(database, changes); + boolean changesHandled = changeDialog.showAndWait().orElse(false); + if (changesHandled) { + monitor.markExternalChangesAsResolved(); + this.hide(); + } + })); + this.show(); + } +} diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangeViewModel.java b/src/main/java/org/jabref/gui/collab/DatabaseChangeViewModel.java new file mode 100644 index 00000000000..88f4d200ed5 --- /dev/null +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangeViewModel.java @@ -0,0 +1,49 @@ +package org.jabref.gui.collab; + +import javafx.scene.Node; + +import org.jabref.gui.undo.NamedCompound; +import org.jabref.model.database.BibDatabaseContext; + +abstract class DatabaseChangeViewModel { + + protected String name; + private boolean accepted = true; + + DatabaseChangeViewModel() { + name = ""; + } + + DatabaseChangeViewModel(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public boolean isAccepted() { + return accepted; + } + + public void setAccepted(boolean a) { + accepted = a; + } + + + /** + * This method returns a JComponent detailing the nature of the change. + * @return JComponent + */ + public abstract Node description(); + + /** + * Performs the change. This method is responsible for adding a proper undo edit to + * the NamedCompound, so the change can be undone. + * @param database the database that should be modified accordingly. + * @param undoEdit NamedCompound The compound to hold the undo edits. + */ + public abstract void makeChange(BibDatabaseContext database, NamedCompound undoEdit); + +} diff --git a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java index 622dc4142cf..a84904534bb 100644 --- a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java @@ -1,49 +1,36 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; - -import javafx.embed.swing.JFXPanel; -import javafx.scene.Scene; +import javafx.scene.Node; import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.FXDialogService; +import org.jabref.JabRefGUI; import org.jabref.gui.PreviewPanel; -import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertEntry; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.IdGenerator; -class EntryAddChangeViewModel extends ChangeViewModel { +class EntryAddChangeViewModel extends DatabaseChangeViewModel { private final BibEntry diskEntry; - private final JFXPanel container; - public EntryAddChangeViewModel(BibEntry diskEntry) { super(Localization.lang("Added entry")); this.diskEntry = diskEntry; - - PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService(), ExternalFileTypes.getInstance()); - previewPanel.setEntry(diskEntry); - container = CustomJFXPanel.wrap(new Scene(previewPanel)); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - diskEntry.setId(IdGenerator.next()); - panel.getDatabase().insertEntry(diskEntry); - secondary.insertEntry(diskEntry); - undoEdit.addEdit(new UndoableInsertEntry(panel.getDatabase(), diskEntry)); - return true; + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + database.getDatabase().insertEntry(diskEntry); + undoEdit.addEdit(new UndoableInsertEntry(database.getDatabase(), diskEntry)); } @Override - public JComponent description() { - return container; + public Node description() { + PreviewPanel previewPanel = new PreviewPanel(null, new BibDatabaseContext(), Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), JabRefGUI.getMainFrame().getDialogService(), ExternalFileTypes.getInstance()); + previewPanel.setEntry(diskEntry); + return previewPanel; } } diff --git a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java index d2bdea57401..fcad087163d 100644 --- a/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryChangeViewModel.java @@ -1,39 +1,36 @@ package org.jabref.gui.collab; -import java.util.Collections; -import java.util.Enumeration; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.TreeSet; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JScrollPane; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.l10n.Localization; -import org.jabref.model.TreeNode; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class EntryChangeViewModel extends ChangeViewModel { +class EntryChangeViewModel extends DatabaseChangeViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(EntryChangeViewModel.class); + private final List fieldChanges = new ArrayList<>(); + public EntryChangeViewModel(BibEntry memEntry, BibEntry tmpEntry, BibEntry diskEntry) { super(); - Optional key = tmpEntry.getCiteKeyOptional(); - if (key.isPresent()) { - name = Localization.lang("Modified entry") + ": '" + key.get() + '\''; - } else { - name = Localization.lang("Modified entry"); - } + name = tmpEntry.getCiteKeyOptional() + .map(key -> Localization.lang("Modified entry") + ": '" + key + '\'') + .orElse(Localization.lang("Modified entry")); // We know that tmpEntry is not equal to diskEntry. Check if it has been modified // locally as well, since last tempfile was saved. @@ -59,57 +56,48 @@ public EntryChangeViewModel(BibEntry memEntry, BibEntry tmpEntry, BibEntry diskE if ((tmp.isPresent()) && (disk.isPresent())) { if (!tmp.equals(disk)) { // Modified externally. - add(new FieldChangeViewModel(field, memEntry, tmpEntry, mem.orElse(null), tmp.get(), disk.get())); + fieldChanges.add(new FieldChangeViewModel(field, memEntry, tmpEntry, mem.orElse(null), tmp.get(), disk.get())); } } else if (((!tmp.isPresent()) && (disk.isPresent()) && !disk.get().isEmpty()) || ((!disk.isPresent()) && (tmp.isPresent()) && !tmp.get().isEmpty() && (mem.isPresent()) && !mem.get().isEmpty())) { // Added externally. - add(new FieldChangeViewModel(field, memEntry, tmpEntry, mem.orElse(null), tmp.orElse(null), - disk.orElse(null))); + fieldChanges.add(new FieldChangeViewModel(field, memEntry, tmpEntry, mem.orElse(null), tmp.orElse(null), disk.orElse(null))); } } } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - boolean allAccepted = true; - - // TODO: Java 9: Generics are stronger? - Enumeration e = children(); - for (javax.swing.tree.TreeNode c : Collections.list(e)) { - ChangeViewModel model = (ChangeViewModel) c; - if (model.isAcceptable() && model.isAccepted()) { - model.makeChange(panel, secondary, undoEdit); - } else { - allAccepted = false; + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + for (DatabaseChangeViewModel c : fieldChanges) { + if (c.isAccepted()) { + c.makeChange(database, undoEdit); } } - - /*panel.database().removeEntry(memEntry.getId()); - try { - diskEntry.setId(Util.next()); - } catch (KeyCollisionException ex) {} - panel.database().removeEntry(memEntry.getId());*/ - - return allAccepted; } @Override - public JComponent description() { - return new JLabel(name); + public Node description() { + VBox container = new VBox(); + Label header = new Label(name); + header.getStyleClass().add("sectionHeader"); + container.getChildren().add(header); + + for (FieldChangeViewModel change : fieldChanges) { + container.getChildren().add(change.description()); + } + + return container; } - static class FieldChangeViewModel extends ChangeViewModel { + static class FieldChangeViewModel extends DatabaseChangeViewModel { private final BibEntry entry; private final BibEntry tmpEntry; private final String field; private final String inMem; + private final String onTmp; private final String onDisk; - private final InfoPane tp = new InfoPane(); - private final JScrollPane sp = new JScrollPane(tp); - public FieldChangeViewModel(String field, BibEntry memEntry, BibEntry tmpEntry, String inMem, String onTmp, String onDisk) { super(field); @@ -117,47 +105,39 @@ public FieldChangeViewModel(String field, BibEntry memEntry, BibEntry tmpEntry, this.tmpEntry = tmpEntry; this.field = field; this.inMem = inMem; + this.onTmp = onTmp; this.onDisk = onDisk; - - StringBuilder text = new StringBuilder(36); - text.append("

").append(Localization.lang("Modification of field")) - .append(" ").append(field).append("

"); - - if ((onDisk != null) && !onDisk.isEmpty()) { - text.append("

").append(Localization.lang("Value set externally")).append(":

").append(onDisk); - } else { - text.append("

").append(Localization.lang("Value cleared externally")).append("

"); - } - - if ((inMem != null) && !inMem.isEmpty()) { - text.append("

").append(Localization.lang("Current value")).append(":

").append(inMem); - } - if ((onTmp != null) && !onTmp.isEmpty()) { - text.append("

").append(Localization.lang("Current tmp value")).append(":

").append(onTmp); - } - tp.setContentType("text/html"); - tp.setText(text.toString()); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { if (onDisk == null) { entry.clearField(field); } else { entry.setField(field, onDisk); } undoEdit.addEdit(new UndoableFieldChange(entry, field, inMem, onDisk)); - if (onDisk == null) { - tmpEntry.clearField(field); - } else { - tmpEntry.setField(field, onDisk); - } - return true; } @Override - public JComponent description() { - return sp; + public Node description() { + VBox container = new VBox(); + container.getChildren().add(new Label(Localization.lang("Modification of field") + " " + field)); + + if ((onDisk != null) && !onDisk.isEmpty()) { + container.getChildren().add(new Label(Localization.lang("Value set externally") + ": " + onDisk)); + } else { + container.getChildren().add(new Label(Localization.lang("Value cleared externally"))); + } + + if ((inMem != null) && !inMem.isEmpty()) { + container.getChildren().add(new Label(Localization.lang("Current value") + ": " + inMem)); + } + if ((onTmp != null) && !onTmp.isEmpty()) { + container.getChildren().add(new Label(Localization.lang("Current tmp value") + ": " + onTmp)); + } + + return container; } } diff --git a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java index 37511d67830..3efe55cb530 100644 --- a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java @@ -1,35 +1,27 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; - -import javafx.embed.swing.JFXPanel; -import javafx.scene.Scene; +import javafx.scene.Node; import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.FXDialogService; +import org.jabref.JabRefGUI; import org.jabref.gui.PreviewPanel; -import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableRemoveEntry; import org.jabref.logic.bibtex.DuplicateCheck; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class EntryDeleteChangeViewModel extends ChangeViewModel { +class EntryDeleteChangeViewModel extends DatabaseChangeViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(EntryDeleteChangeViewModel.class); private final BibEntry memEntry; private final BibEntry tmpEntry; - private final JFXPanel container; - - public EntryDeleteChangeViewModel(BibEntry memEntry, BibEntry tmpEntry) { super(Localization.lang("Deleted entry")); this.memEntry = memEntry; @@ -44,22 +36,18 @@ public EntryDeleteChangeViewModel(BibEntry memEntry, BibEntry tmpEntry) { LOGGER.debug("Modified entry: " + memEntry.getCiteKeyOptional().orElse("") + "\n Modified locally: " + isModifiedLocally); - - PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService(), ExternalFileTypes.getInstance()); - previewPanel.setEntry(memEntry); - container = CustomJFXPanel.wrap(new Scene(previewPanel)); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - panel.getDatabase().removeEntry(memEntry); - undoEdit.addEdit(new UndoableRemoveEntry(panel.getDatabase(), memEntry, panel)); - secondary.removeEntry(tmpEntry); - return true; + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + database.getDatabase().removeEntry(memEntry); + undoEdit.addEdit(new UndoableRemoveEntry(database.getDatabase(), memEntry, null)); } @Override - public JComponent description() { - return container; + public Node description() { + PreviewPanel previewPanel = new PreviewPanel(null, new BibDatabaseContext(), Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), JabRefGUI.getMainFrame().getDialogService(), ExternalFileTypes.getInstance()); + previewPanel.setEntry(memEntry); + return previewPanel; } } diff --git a/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java b/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java deleted file mode 100644 index ea270674a02..00000000000 --- a/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.jabref.gui.collab; - -import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; - -import javafx.embed.swing.SwingNode; -import javafx.scene.Node; -import javafx.scene.layout.Priority; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.SidePaneComponent; -import org.jabref.gui.SidePaneManager; -import org.jabref.gui.SidePaneType; -import org.jabref.gui.actions.Action; -import org.jabref.gui.icon.IconTheme; -import org.jabref.logic.l10n.Localization; - -public class FileUpdatePanel extends SidePaneComponent implements ActionListener, ChangeScanner.DisplayResultCallback { - - private final SidePaneManager manager; - private ChangeScanner scanner; - private File file; - private BasePanel panel; - - public FileUpdatePanel(SidePaneManager manager) { - super(manager, IconTheme.JabRefIcons.SAVE, Localization.lang("File changed")); - - this.manager = manager; - } - - public void showForFile(BasePanel panel, File file, ChangeScanner scanner) { - this.file = file; - this.panel = panel; - this.scanner = scanner; - - this.show(); - } - - /** - * We include a getter for the BasePanel this component refers to, because this - * component needs to be closed if the BasePanel is closed. - * @return the base panel this component refers to. - */ - public BasePanel getPanel() { - return panel; - } - - @Override - public Priority getResizePolicy() { - return Priority.NEVER; - } - - @Override - public ToggleCommand getToggleCommand() { - throw new UnsupportedOperationException(); - } - - @Override - public Action getToggleAction() { - throw new UnsupportedOperationException(); - } - - @Override - protected Node createContentPane() { - JPanel main = new JPanel(); - main.setLayout(new BorderLayout()); - - JLabel message = new JLabel("
" - + Localization.lang("The file
'%0'
has been modified
externally!", file.getName()) - + "
", SwingConstants.CENTER); - - main.add(message, BorderLayout.CENTER); - JButton reviewChanges = new JButton(Localization.lang("Review changes")); - reviewChanges.addActionListener(this); - main.add(reviewChanges, BorderLayout.SOUTH); - main.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); - - SwingNode swingNode = new SwingNode(); - SwingUtilities.invokeLater(() -> swingNode.setContent(main)); - return swingNode; - } - - @Override - public SidePaneType getType() { - return SidePaneType.FILE_UPDATE_NOTIFICATION; - } - - /** - * actionPerformed - * - * @param e - * ActionEvent - */ - @Override - public void actionPerformed(ActionEvent e) { - - // ChangeScanner scanner = new ChangeScanner(frame, panel); //, - // panel.database(), panel.metaData()); - // try { - scanner.displayResult(this); - // scanner.changeScan(panel.file()); - - // } catch (IOException ex) { - // ex.printStackTrace(); - // } - } - - /** - * Callback method for signalling that the change scanner has displayed the - * scan results to the user. - * @param resolved true if there were no changes, or if the user has resolved them. - */ - @Override - public void scanResultsResolved(boolean resolved) { - if (resolved) { - manager.hide(this.getType()); - panel.markExternalChangesAsResolved(); - } - } -} diff --git a/src/main/java/org/jabref/gui/collab/GroupChangeViewModel.java b/src/main/java/org/jabref/gui/collab/GroupChangeViewModel.java index 99826a5886c..e6b75feaa38 100644 --- a/src/main/java/org/jabref/gui/collab/GroupChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/GroupChangeViewModel.java @@ -1,40 +1,36 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JLabel; +import javafx.scene.Node; +import javafx.scene.control.Label; -import org.jabref.gui.BasePanel; import org.jabref.gui.groups.GroupTreeNodeViewModel; import org.jabref.gui.groups.UndoableModifySubtree; import org.jabref.gui.undo.NamedCompound; import org.jabref.logic.bibtex.comparator.GroupDiff; import org.jabref.logic.groups.DefaultGroupsFactory; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.groups.GroupTreeNode; -class GroupChangeViewModel extends ChangeViewModel { +class GroupChangeViewModel extends DatabaseChangeViewModel { private final GroupTreeNode changedGroups; - private final GroupTreeNode tmpGroupRoot; - public GroupChangeViewModel(GroupDiff diff) { super(diff.getOriginalGroupRoot() == null ? Localization.lang("Removed all groups") : Localization .lang("Modified groups tree")); - this.changedGroups = diff.getOriginalGroupRoot(); - this.tmpGroupRoot = diff.getNewGroupRoot(); + this.changedGroups = diff.getNewGroupRoot(); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - GroupTreeNode root = panel.getBibDatabaseContext().getMetaData().getGroups().orElse(null); + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + GroupTreeNode root = database.getMetaData().getGroups().orElse(null); if (root == null) { root = new GroupTreeNode(DefaultGroupsFactory.getAllEntriesGroup()); - panel.getBibDatabaseContext().getMetaData().setGroups(root); + database.getMetaData().setGroups(root); } final UndoableModifySubtree undo = new UndoableModifySubtree( - new GroupTreeNodeViewModel(panel.getBibDatabaseContext().getMetaData().getGroups().orElse(null)), + new GroupTreeNodeViewModel(database.getMetaData().getGroups().orElse(null)), new GroupTreeNodeViewModel(root), Localization.lang("Modified groups")); root.removeAllChildren(); if (changedGroups == null) { @@ -49,28 +45,13 @@ public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound } undoEdit.addEdit(undo); - - // Update tmp database: - if (tmpGroupRoot != null) { - tmpGroupRoot.removeAllChildren(); - if (changedGroups != null) { - GroupTreeNode copied = changedGroups.copySubtree(); - tmpGroupRoot.setGroup(copied.getGroup()); - for (GroupTreeNode child : copied.getChildren()) { - child.copySubtree().moveTo(tmpGroupRoot); - } - } - } - - return true; } @Override - public JComponent description() { - return new JLabel("" + toString() + '.' + public Node description() { + return new Label(toString() + '.' + (changedGroups == null ? "" : ' ' + Localization - .lang("Accepting the change replaces the complete groups tree with the externally modified groups tree.")) - + ""); + .lang("Accepting the change replaces the complete groups tree with the externally modified groups tree."))); } } diff --git a/src/main/java/org/jabref/gui/collab/InfoPane.java b/src/main/java/org/jabref/gui/collab/InfoPane.java deleted file mode 100644 index cec4658a5de..00000000000 --- a/src/main/java/org/jabref/gui/collab/InfoPane.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.jabref.gui.collab; - -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; - -import javax.swing.JEditorPane; - -class InfoPane extends JEditorPane { - - public InfoPane() { - setEditable(false); - setContentType("text/html"); - } - - @Override - public void paint(Graphics g) { - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - super.paint(g2); - } -} diff --git a/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java b/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java index 7418ff1695f..83b5b7f7b56 100644 --- a/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java @@ -1,30 +1,25 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JScrollPane; +import javafx.scene.Node; +import javafx.scene.control.Label; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.logic.bibtex.comparator.MetaDataDiff; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.metadata.MetaData; -class MetaDataChangeViewModel extends ChangeViewModel { +class MetaDataChangeViewModel extends DatabaseChangeViewModel { - private final InfoPane infoPane = new InfoPane(); - private final JScrollPane sp = new JScrollPane(infoPane); private final MetaData newMetaData; public MetaDataChangeViewModel(MetaDataDiff metaDataDiff) { super(Localization.lang("Metadata change")); this.newMetaData = metaDataDiff.getNewMetaData(); - - infoPane.setText("" + Localization.lang("Metadata change") + ""); } @Override - public JComponent description() { + public Node description() { /* // TODO: Show detailed description of the changes StringBuilder sb = new StringBuilder( @@ -34,12 +29,11 @@ public JComponent description() { sb.append(""); infoPane.setText(sb.toString()); */ - return sp; + return new Label(Localization.lang("Metadata change")); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - panel.getBibDatabaseContext().setMetaData(newMetaData); - return true; + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + database.setMetaData(newMetaData); } } diff --git a/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java b/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java index a3f707b5cd5..b8a17ccb840 100644 --- a/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java @@ -1,54 +1,48 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JScrollPane; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoablePreambleChange; import org.jabref.logic.bibtex.comparator.PreambleDiff; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.strings.StringUtil; -class PreambleChangeViewModel extends ChangeViewModel { +class PreambleChangeViewModel extends DatabaseChangeViewModel { - private final String mem; - private final String disk; - private final InfoPane tp = new InfoPane(); - private final JScrollPane sp = new JScrollPane(tp); + private final PreambleDiff change; - public PreambleChangeViewModel(String mem, PreambleDiff diff) { + public PreambleChangeViewModel(PreambleDiff change) { super(Localization.lang("Changed preamble")); - this.disk = diff.getNewPreamble(); - this.mem = mem; - - StringBuilder text = new StringBuilder(34); - text.append("

").append(Localization.lang("Changed preamble")).append("

"); - - if (StringUtil.isNotBlank(disk)) { - text.append("

").append(Localization.lang("Value set externally")).append(":

" + "").append(disk).append(""); - } else { - text.append("

").append(Localization.lang("Value cleared externally")).append("

"); - } - - if (StringUtil.isNotBlank(mem)) { - text.append("

").append(Localization.lang("Current value")).append(":

" + "").append(mem).append(""); - } - - tp.setText(text.toString()); + this.change = change; } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - panel.getDatabase().setPreamble(disk); - undoEdit.addEdit(new UndoablePreambleChange(panel.getDatabase(), mem, disk)); - secondary.setPreamble(disk); - return true; + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + database.getDatabase().setPreamble(change.getNewPreamble()); + undoEdit.addEdit(new UndoablePreambleChange(database.getDatabase(), change.getOriginalPreamble(), change.getNewPreamble())); } @Override - public JComponent description() { - return sp; + public Node description() { + VBox container = new VBox(); + Label header = new Label(Localization.lang("Changed preamble")); + header.getStyleClass().add("sectionHeader"); + container.getChildren().add(header); + + if (StringUtil.isNotBlank(change.getOriginalPreamble())) { + container.getChildren().add(new Label(Localization.lang("Current value") + ": " + change.getOriginalPreamble())); + } + + if (StringUtil.isNotBlank(change.getNewPreamble())) { + container.getChildren().add(new Label(Localization.lang("Value set externally") + ": " + change.getNewPreamble())); + } else { + container.getChildren().add(new Label(Localization.lang("Value cleared externally"))); + } + + return container; } } diff --git a/src/main/java/org/jabref/gui/collab/StringAddChangeViewModel.java b/src/main/java/org/jabref/gui/collab/StringAddChangeViewModel.java index 20bf1099ef6..f22535b875b 100644 --- a/src/main/java/org/jabref/gui/collab/StringAddChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/StringAddChangeViewModel.java @@ -1,63 +1,50 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JScrollPane; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertString; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.KeyCollisionException; import org.jabref.model.entry.BibtexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class StringAddChangeViewModel extends ChangeViewModel { +class StringAddChangeViewModel extends DatabaseChangeViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(StringAddChangeViewModel.class); - private final BibtexString string; - private final InfoPane tp = new InfoPane(); - - private final JScrollPane sp = new JScrollPane(tp); - public StringAddChangeViewModel(BibtexString string) { super(Localization.lang("Added string") + ": '" + string.getName() + '\''); this.string = string; - tp.setText("

" + Localization.lang("Added string") + "

" + - Localization.lang("Label") + ":

" + string.getName() + "

" + - Localization.lang("Content") + ":

" + string.getContent() + ""); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - - if (panel.getDatabase().hasStringLabel(string.getName())) { - // The name to change to is already in the database, so we can't comply. - LOGGER.info("Cannot add string '" + string.getName() + "' because the name " - + "is already in use."); - } - - try { - panel.getDatabase().addString(string); - undoEdit.addEdit(new UndoableInsertString(panel, panel.getDatabase(), string)); - } catch (KeyCollisionException ex) { - LOGGER.info("Error: could not add string '" + string.getName() + "': " + ex.getMessage(), ex); - } + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { try { - secondary.addString(new BibtexString(string.getName(), string.getContent())); + database.getDatabase().addString(string); + undoEdit.addEdit(new UndoableInsertString(database.getDatabase(), string)); } catch (KeyCollisionException ex) { - LOGGER.info("Error: could not add string '" + string.getName() + "' to tmp database: " + ex.getMessage(), ex); + LOGGER.warn("Error: could not add string '" + string.getName() + "': " + ex.getMessage(), ex); } - return true; } @Override - public JComponent description() { - return sp; + public Node description() { + VBox container = new VBox(); + Label header = new Label(Localization.lang("Added string")); + header.getStyleClass().add("sectionHeader"); + container.getChildren().addAll( + header, + new Label(Localization.lang("Label") + ": " + string.getName()), + new Label(Localization.lang("Content") + ": " + string.getContent()) + ); + return container; } } diff --git a/src/main/java/org/jabref/gui/collab/StringChangeViewModel.java b/src/main/java/org/jabref/gui/collab/StringChangeViewModel.java index 19e68f3a0b9..278715f4b43 100644 --- a/src/main/java/org/jabref/gui/collab/StringChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/StringChangeViewModel.java @@ -1,88 +1,70 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JScrollPane; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertString; import org.jabref.gui.undo.UndoableStringChange; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.KeyCollisionException; import org.jabref.model.entry.BibtexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class StringChangeViewModel extends ChangeViewModel { +class StringChangeViewModel extends DatabaseChangeViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(StringChangeViewModel.class); private final BibtexString string; private final String disk; - private final String label; - private final InfoPane tp = new InfoPane(); - private final JScrollPane sp = new JScrollPane(tp); - - private final BibtexString tmpString; - public StringChangeViewModel(BibtexString string, BibtexString tmpString, String disk) { super(Localization.lang("Modified string") + ": '" + tmpString.getName() + '\''); - this.tmpString = tmpString; this.string = string; this.label = tmpString.getName(); this.disk = disk; - - StringBuilder sb = new StringBuilder(46); - sb.append("

").append(Localization.lang("Modified string")).append("

") - .append(Localization.lang("Label")).append(":

").append(label).append("

") - .append(Localization.lang("New content")).append(":

").append(disk); - if (string == null) { - sb.append("

"); - sb.append(Localization.lang("Cannot merge this change")).append(": "); - sb.append(Localization.lang("The string has been removed locally")).append(""); - } else { - sb.append("

"); - sb.append(Localization.lang("Current content")).append(":

"); - sb.append(string.getContent()); - } - sb.append(""); - tp.setText(sb.toString()); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { if (string == null) { // The string was removed or renamed locally. We guess that it was removed. BibtexString bs = new BibtexString(label, disk); try { - panel.getDatabase().addString(bs); - undoEdit.addEdit(new UndoableInsertString(panel, panel.getDatabase(), bs)); + database.getDatabase().addString(bs); + undoEdit.addEdit(new UndoableInsertString(database.getDatabase(), bs)); } catch (KeyCollisionException ex) { - LOGGER.info("Error: could not add string '" + bs.getName() + "': " + ex.getMessage(), ex); + LOGGER.warn("Error: could not add string '" + bs.getName() + "': " + ex.getMessage(), ex); } } else { String mem = string.getContent(); string.setContent(disk); - undoEdit.addEdit(new UndoableStringChange(panel, string, false, mem, disk)); + undoEdit.addEdit(new UndoableStringChange(string, false, mem, disk)); } + } - // Update tmp database: - if (tmpString == null) { - BibtexString bs = new BibtexString(label, disk); - secondary.addString(bs); + @Override + public Node description() { + VBox container = new VBox(); + Label header = new Label(Localization.lang("Modified string")); + header.getStyleClass().add("sectionHeader"); + container.getChildren().addAll( + header, + new Label(Localization.lang("Label") + ": " + label), + new Label(Localization.lang("Content") + ": " + disk) + ); + + if (string == null) { + container.getChildren().add(new Label(Localization.lang("Cannot merge this change") + ": " + Localization.lang("The string has been removed locally"))); } else { - tmpString.setContent(disk); + container.getChildren().add(new Label(Localization.lang("Current content") + ": " + string.getContent())); } - return true; - } - - @Override - public JComponent description() { - return sp; + return container; } } diff --git a/src/main/java/org/jabref/gui/collab/StringNameChangeViewModel.java b/src/main/java/org/jabref/gui/collab/StringNameChangeViewModel.java index e9bda7c9f40..77aebba89e1 100644 --- a/src/main/java/org/jabref/gui/collab/StringNameChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/StringNameChangeViewModel.java @@ -1,21 +1,20 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JLabel; +import javafx.scene.Node; +import javafx.scene.control.Label; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertString; import org.jabref.gui.undo.UndoableStringChange; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.KeyCollisionException; import org.jabref.model.entry.BibtexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class StringNameChangeViewModel extends ChangeViewModel { +class StringNameChangeViewModel extends DatabaseChangeViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(StringNameChangeViewModel.class); private final BibtexString string; @@ -23,23 +22,17 @@ class StringNameChangeViewModel extends ChangeViewModel { private final String disk; private final String content; - private final BibtexString tmpString; - - public StringNameChangeViewModel(BibtexString string, BibtexString tmpString, String mem, String disk) { super(Localization.lang("Renamed string") + ": '" + tmpString.getName() + '\''); - this.tmpString = tmpString; this.string = string; this.content = tmpString.getContent(); this.mem = mem; this.disk = disk; - } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - - if (panel.getDatabase().hasStringLabel(disk)) { + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { + if (database.getDatabase().hasStringLabel(disk)) { // The name to change to is already in the database, so we can't comply. LOGGER.info("Cannot rename string '" + mem + "' to '" + disk + "' because the name " + "is already in use."); @@ -49,30 +42,20 @@ public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound // The string was removed or renamed locally. We guess that it was removed. BibtexString bs = new BibtexString(disk, content); try { - panel.getDatabase().addString(bs); - undoEdit.addEdit(new UndoableInsertString(panel, panel.getDatabase(), bs)); + database.getDatabase().addString(bs); + undoEdit.addEdit(new UndoableInsertString(database.getDatabase(), bs)); } catch (KeyCollisionException ex) { LOGGER.info("Error: could not add string '" + bs.getName() + "': " + ex.getMessage(), ex); } } else { string.setName(disk); - undoEdit.addEdit(new UndoableStringChange(panel, string, true, mem, disk)); + undoEdit.addEdit(new UndoableStringChange(string, true, mem, disk)); } - - // Update tmp database: - if (tmpString == null) { - BibtexString bs = new BibtexString(disk, content); - secondary.addString(bs); - } else { - tmpString.setName(disk); - } - - return true; } @Override - public JComponent description() { - return new JLabel(disk + " : " + content); + public Node description() { + return new Label(disk + " : " + content); } } diff --git a/src/main/java/org/jabref/gui/collab/StringRemoveChangeViewModel.java b/src/main/java/org/jabref/gui/collab/StringRemoveChangeViewModel.java index 4501888a240..ba1b8066afb 100644 --- a/src/main/java/org/jabref/gui/collab/StringRemoveChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/StringRemoveChangeViewModel.java @@ -1,55 +1,51 @@ package org.jabref.gui.collab; -import javax.swing.JComponent; -import javax.swing.JScrollPane; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; -import org.jabref.gui.BasePanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableRemoveString; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabase; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibtexString; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class StringRemoveChangeViewModel extends ChangeViewModel { +class StringRemoveChangeViewModel extends DatabaseChangeViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(StringRemoveChangeViewModel.class); private final BibtexString string; private final BibtexString inMem; - private final InfoPane tp = new InfoPane(); - private final JScrollPane sp = new JScrollPane(tp); public StringRemoveChangeViewModel(BibtexString string, BibtexString inMem) { super(Localization.lang("Removed string") + ": '" + string.getName() + '\''); this.string = string; this.inMem = inMem; // Holds the version in memory. Check if it has been modified...? - - tp.setText("

" + Localization.lang("Removed string") + "

" + - Localization.lang("Label") + ":

" + string.getName() + "

" + - Localization.lang("Content") + ":

" + string.getContent() + ""); } @Override - public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { - + public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { try { - panel.getDatabase().removeString(inMem.getId()); - undoEdit.addEdit(new UndoableRemoveString(panel, panel.getDatabase(), string)); + database.getDatabase().removeString(inMem.getId()); + undoEdit.addEdit(new UndoableRemoveString(database.getDatabase(), string)); } catch (Exception ex) { - LOGGER.info("Error: could not add string '" + string.getName() + "': " + ex.getMessage(), ex); + LOGGER.warn("Error: could not add string '" + string.getName() + "': " + ex.getMessage(), ex); } - - // Update tmp database: - secondary.removeString(string.getId()); - - return true; } @Override - public JComponent description() { - return sp; + public Node description() { + VBox container = new VBox(); + Label header = new Label(Localization.lang("Removed string")); + header.getStyleClass().add("sectionHeader"); + container.getChildren().addAll( + header, + new Label(Localization.lang("Label") + ": " + string.getName()), + new Label(Localization.lang("Content") + ": " + string.getContent()) + ); + return container; } } diff --git a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml new file mode 100644 index 00000000000..94744038b42 --- /dev/null +++ b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.fxml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java deleted file mode 100644 index a188c1fca8a..00000000000 --- a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java +++ /dev/null @@ -1,499 +0,0 @@ -package org.jabref.gui.contentselector; - -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.BorderFactory; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefDialog; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.help.HelpAction; -import org.jabref.gui.keyboard.KeyBinder; -import org.jabref.logic.help.HelpFile; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.FieldName; -import org.jabref.model.metadata.ContentSelector; -import org.jabref.model.metadata.ContentSelectors; -import org.jabref.model.metadata.MetaData; - -import com.jgoodies.forms.builder.ButtonBarBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ContentSelectorDialog extends JabRefDialog { - - private static final String WORD_FIRSTLINE_TEXT = Localization.lang(" Abbreviate\ journal\ names\ of\ the\ selected\ entries\ (ISO\ abbreviation)=Abbreviate journal names of the selected entries (ISO abbreviation) Abbreviate\ journal\ names\ of\ the\ selected\ entries\ (MEDLINE\ abbreviation)=Abbreviate journal names of the selected entries (MEDLINE abbreviation) @@ -46,8 +43,6 @@ Add\ selected\ entries\ to\ this\ group=Add selected entries to this group Add\ subgroup=Add subgroup -Add\ to\ group=Add to group - Added\ group\ "%0".=Added group "%0". Added\ string=Added string @@ -66,12 +61,10 @@ any\ field\ that\ matches\ the\ regular\ expression\ %0=any field that ma Appearance=Appearance -Append=Append Append\ contents\ from\ a\ BibTeX\ library\ into\ the\ currently\ viewed\ library=Append contents from a BibTeX library into the currently viewed library Append\ library=Append library -Append\ the\ selected\ text\ to\ BibTeX\ field=Append the selected text to BibTeX field Application=Application Apply=Apply @@ -84,8 +77,6 @@ Assigned\ %0\ entries\ to\ group\ "%1".=Assigned %0 entries to group "%1". Assigned\ 1\ entry\ to\ group\ "%0".=Assigned 1 entry to group "%0". -Attach\ URL=Attach URL - Autogenerate\ BibTeX\ keys=Autogenerate BibTeX keys Autolink\ files\ with\ names\ starting\ with\ the\ BibTeX\ key=Autolink files with names starting with the BibTeX key @@ -100,8 +91,6 @@ AUX\ file\ import=AUX file import Available\ export\ formats=Available export formats -Available\ BibTeX\ fields=Available BibTeX fields - Available\ import\ formats=Available import formats Backup\ old\ file\ when\ saving=Backup old file when saving @@ -114,8 +103,9 @@ by=by The\ conflicting\ fields\ of\ these\ entries\ will\ be\ merged\ into\ the\ 'Comment'\ field.=The conflicting fields of these entries will be merged into the 'Comment' field. Cancel=Cancel +Cannot\ create\ group=Cannot create group -Cannot\ add\ entries\ to\ group\ without\ generating\ keys.\ Generate\ keys\ now?=Cannot add entries to group without generating keys. Generate keys now? +Cannot\ create\ group.\ Please\ create\ a\ library\ first.=Cannot create group. Please create a library first. Cannot\ merge\ this\ change=Cannot merge this change @@ -136,8 +126,6 @@ Change\ of\ Grouping\ Method=Change of Grouping Method change\ preamble=change preamble -Change\ table\ column\ and\ General\ fields\ settings\ to\ use\ the\ new\ feature=Change table column and General fields settings to use the new feature - Changed\ language\ settings=Changed language settings Changed\ preamble=Changed preamble @@ -177,7 +165,6 @@ Copied\ keys=Copied keys Copy=Copy Copy\ BibTeX\ key=Copy BibTeX key -Copy\ file\ to\ file\ directory=Copy file to file directory Copy\ to\ clipboard=Copy to clipboard @@ -238,7 +225,6 @@ Default\ encoding=Default encoding Default\ grouping\ field=Default grouping field Default\ pattern=Default pattern - Execute\ default\ action\ in\ dialog=Execute default action in dialog Delete=Delete @@ -255,8 +241,6 @@ Delete\ multiple\ entries=Delete multiple entries Delete\ rows=Delete rows -Delete\ strings=Delete strings - Deleted=Deleted Permanently\ delete\ local\ file=Permanently delete local file @@ -265,9 +249,6 @@ Descending=Descending Description=Description -Deselect\ all=Deselect all -Deselect\ all\ duplicates=Deselect all duplicates - Disable\ this\ confirmation\ dialog=Disable this confirmation dialog Display\ all\ entries\ belonging\ to\ one\ or\ more\ of\ the\ selected\ groups.=Display all entries belonging to one or more of the selected groups. @@ -286,23 +267,15 @@ Do\ not\ import\ entry=Do not import entry Do\ not\ open\ any\ files\ at\ startup=Do not open any files at startup Do\ not\ overwrite\ existing\ keys=Do not overwrite existing keys -Do\ not\ show\ these\ options\ in\ the\ future=Do not show these options in the future Do\ not\ wrap\ the\ following\ fields\ when\ saving=Do not wrap the following fields when saving Do\ not\ write\ the\ following\ fields\ to\ XMP\ Metadata\:=Do not write the following fields to XMP Metadata: -Do\ you\ want\ JabRef\ to\ do\ the\ following\ operations?=Do you want JabRef to do the following operations? - Donate\ to\ JabRef=Donate to JabRef Down=Down Download\ file=Download file - -Downloading...=Downloading... - -Drop\ %0=Drop %0 - duplicate\ removal=duplicate removal Duplicate\ string\ name=Duplicate string name @@ -320,7 +293,6 @@ Each\ line\ must\ be\ of\ the\ following\ form=Each line must be of the followin Edit=Edit Edit\ entry=Edit entry -Save\ file=Save file Edit\ file\ type=Edit file type Edit\ group=Edit group @@ -333,8 +305,6 @@ Editor\ options=Editor options empty\ library=empty library Enable\ word/name\ autocompletion=Enable word/name autocompletion -Enter\ URL=Enter URL - Enter\ URL\ to\ download=Enter URL to download entries=entries @@ -353,7 +323,6 @@ Entry\ preview=Entry preview Entry\ table=Entry table Entry\ table\ columns=Entry table columns - Entry\ Title\ (Required\ to\ deliver\ recommendations.)=Entry Title (Required to deliver recommendations.) Entry\ type=Entry type @@ -373,7 +342,6 @@ Error\ while\ fetching\ from\ Mr.DLib.=Error while fetching from Mr.DLib. Error\ while\ writing=Error while writing '%0'\ exists.\ Overwrite\ file?='%0' exists. Overwrite file? -Overwrite\ file?=Overwrite file? Export=Export @@ -409,16 +377,11 @@ File=File file=file File\ '%0'\ is\ already\ open.=File '%0' is already open. - -File\ changed=File changed -File\ directory\ is\ '%0'\:=File directory is '%0': - File\ directory\ is\ not\ set\ or\ does\ not\ exist\!=File directory is not set or does not exist! File\ exists=File exists File\ not\ found=File not found -File\ type=File type filename=filename Files\ opened=Files opened @@ -434,9 +397,6 @@ First\ select\ the\ entries\ you\ want\ keys\ to\ be\ generated\ for.=First sele Fit\ table\ horizontally\ on\ screen=Fit table horizontally on screen Float=Float - -for=for - Format\:\ Tab\:field;field;...\ (e.g.\ General\:url;pdf;note...)=Format\: Tab\:field;field;... (e.g. General\:url;pdf;note...) Format\ of\ author\ and\ editor\ names=Format of author and editor names @@ -447,8 +407,6 @@ Formatter\ name=Formatter name found\ in\ AUX\ file=found in AUX file -Full\ name=Full name - Further\ information\ about\ Mr\ DLib.\ for\ JabRef\ users.=Further information about Mr DLib. for JabRef users. General=General @@ -462,9 +420,6 @@ Generate\ BibTeX\ key=Generate BibTeX key Generate\ keys=Generate keys Generate\ keys\ before\ saving\ (for\ entries\ without\ a\ key)=Generate keys before saving (for entries without a key) -Generate\ keys\ for\ imported\ entries=Generate keys for imported entries - -Generate\ now=Generate now Generated\ BibTeX\ key\ for=Generated BibTeX key for @@ -510,9 +465,6 @@ Import\ and\ keep\ old\ entry=Import and keep old entry Import\ and\ remove\ old\ entry=Import and remove old entry Import\ entries=Import entries - -Import\ failed=Import failed - Import\ file=Import file Import\ group\ definitions=Import group definitions @@ -542,13 +494,7 @@ Importing\ in\ unknown\ format=Importing in unknown format Include\ subgroups\:\ When\ selected,\ view\ entries\ contained\ in\ this\ group\ or\ its\ subgroups=Include subgroups: When selected, view entries contained in this group or its subgroups Independent\ group\:\ When\ selected,\ view\ only\ this\ group's\ entries=Independent group: When selected, view only this group's entries - -Work\ options=Work options - I\ Agree=I Agree - -Insert=Insert - Insert\ rows=Insert rows Intersection=Intersection @@ -560,23 +506,13 @@ Invalid\ date\ format=Invalid date format Invalid\ URL=Invalid URL Online\ help=Online help - JabRef\ Language\ (Provides\ for\ better\ recommendations\ by\ giving\ an\ indication\ of\ user's\ preferred\ language.)=JabRef Language (Provides for better recommendations by giving an indication of user's preferred language.) JabRef\ preferences=JabRef preferences - JabRef\ requests\ recommendations\ from\ Mr.\ DLib,\ which\ is\ an\ external\ service.\ To\ enable\ Mr.\ DLib\ to\ calculate\ recommendations,\ some\ of\ your\ data\ must\ be\ shared\ with\ Mr.\ DLib.\ Generally,\ the\ more\ data\ is\ shared\ the\ better\ recommendations\ can\ be\ calculated.\ However,\ we\ understand\ that\ some\ of\ your\ data\ in\ JabRef\ is\ sensitive,\ and\ you\ may\ not\ want\ to\ share\ it.\ Therefore,\ Mr.\ DLib\ offers\ a\ choice\ of\ which\ data\ you\ would\ like\ to\ share.=JabRef requests recommendations from Mr. DLib, which is an external service. To enable Mr. DLib to calculate recommendations, some of your data must be shared with Mr. DLib. Generally, the more data is shared the better recommendations can be calculated. However, we understand that some of your data in JabRef is sensitive, and you may not want to share it. Therefore, Mr. DLib offers a choice of which data you would like to share. - JabRef\ Version\ (Required\ to\ ensure\ backwards\ compatibility\ with\ Mr.\ DLib's\ Web\ Service)=JabRef Version (Required to ensure backwards compatibility with Mr. DLib's Web Service) -Join=Join - -Joins\ selected\ keywords\ and\ deletes\ selected\ keywords.=Joins selected keywords and deletes selected keywords. - Journal\ abbreviations=Journal abbreviations - -Keep=Keep - Keep\ both=Keep both Key\ bindings=Key bindings @@ -597,14 +533,10 @@ Language=Language Last\ modified=Last modified LaTeX\ AUX\ file\:=LaTeX AUX file\: -Leave\ file\ in\ its\ current\ directory=Leave file in its current directory Left=Left Link=Link -Link\ local\ file=Link local file -Link\ to\ file\ %0=Link to file %0 - Listen\ for\ remote\ operation\ on\ port=Listen for remote operation on port Load\ and\ Save\ preferences\ from/to\ jabref.xml\ on\ start-up\ (memory\ stick\ mode)=Load and Save preferences from/to jabref.xml on start-up (memory stick mode) @@ -636,8 +568,6 @@ Modify=Modify Move\ down=Move down -Move\ external\ links\ to\ 'file'\ field=Move external links to 'file' field - move\ group=move group Move\ up=Move up @@ -650,15 +580,9 @@ Name\ formatter=Name formatter Natbib\ style=Natbib style nested\ AUX\ files=nested AUX files - -New=New - new=new New\ BibTeX\ sublibrary=New BibTeX sublibrary - -New\ content=New content - New\ library\ created.=New library created. New\ group=New group @@ -666,17 +590,11 @@ New\ group=New group New\ string=New string Next\ entry=Next entry - -No\ actual\ changes\ found.=No actual changes found. - no\ base-BibTeX-file\ specified=no base-BibTeX-file specified no\ library\ generated=no library generated No\ entries\ found.\ Please\ make\ sure\ you\ are\ using\ the\ correct\ import\ filter.=No entries found. Please make sure you are using the correct import filter. - -No\ entries\ imported.=No entries imported. - No\ files\ found.=No files found. No\ GUI.\ Only\ process\ command\ line\ options.=No GUI. Only process command line options. @@ -722,7 +640,6 @@ Opened\ library=Opened library Opening=Opening Operation\ canceled.=Operation canceled. - Operating\ System\ (Provides\ for\ better\ recommendations\ by\ giving\ an\ indication\ of\ user's\ system\ set-up.)=Operating System (Provides for better recommendations by giving an indication of user's system set-up.) Optional\ fields=Optional fields @@ -733,13 +650,7 @@ or=or Output\ or\ export\ file=Output or export file -Override=Override - Override\ default\ file\ directories=Override default file directories - -Override\ the\ BibTeX\ field\ by\ the\ selected\ text=Override the BibTeX field by the selected text - - Overwrite=Overwrite Overwrite\ keys=Overwrite keys @@ -752,7 +663,6 @@ Paste=Paste paste\ entries=paste entries paste\ entry=paste entry -Paste\ from\ clipboard=Paste from clipboard Pasted=Pasted @@ -764,8 +674,6 @@ PDF\ does\ not\ exist=PDF does not exist File\ has\ no\ attached\ annotations=File has no attached annotations -Plain\ text\ import=Plain text import - Please\ enter\ a\ name\ for\ the\ group.=Please enter a name for the group. Please\ enter\ a\ search\ term.\ For\ example,\ to\ search\ all\ fields\ for\ Smith,\ enter\:

smith

To\ search\ the\ field\ Author\ for\ Smith\ and\ the\ field\ Title\ for\ electrical,\ enter\:

author\=smith\ and\ title\=electrical=Please enter a search term. For example, to search all fields for Smith, enter:

smith

To search the field Author for Smith and the field Title for electrical, enter:

author=smith and title=electrical @@ -805,8 +713,6 @@ Pushed\ citations\ to\ %0=Pushed citations to %0 Quit\ JabRef=Quit JabRef -Raw\ source=Raw source - Redo=Redo Refine\ supergroup\:\ When\ selected,\ view\ entries\ contained\ in\ both\ this\ group\ and\ its\ supergroup=Refine supergroup: When selected, view entries contained in both this group and its supergroup @@ -831,8 +737,6 @@ Remove\ selected\ entries\ from\ this\ group=Remove selected entries from this g Remove\ entry\ type=Remove entry type -Remove\ from\ group=Remove from group - Remove\ group=Remove group Remove\ group,\ keep\ subgroups=Remove group, keep subgroups @@ -939,8 +843,6 @@ Set\ fields=Set fields Set\ General\ Fields=Set General Fields -Set\ main\ external\ file\ directory=Set main external file directory - Settings=Settings Shortcut=Shortcut @@ -989,9 +891,6 @@ Special\ table\ columns=Special table columns Statically\ group\ entries\ by\ manual\ assignment=Statically group entries by manual assignment Status=Status - -Stop=Stop - Strings\ for\ library=Strings for library Sublibrary\ from\ AUX=Sublibrary from AUX @@ -999,23 +898,15 @@ Sublibrary\ from\ AUX=Sublibrary from AUX Switches\ between\ full\ and\ abbreviated\ journal\ name\ if\ the\ journal\ name\ is\ known.=Switches between full and abbreviated journal name if the journal name is known. Tabname=Tabname -Target\ file\ cannot\ be\ a\ directory.=Target file cannot be a directory. - Tertiary\ sort\ criterion=Tertiary sort criterion Test=Test - -paste\ text\ here=paste text here - The\ chosen\ date\ format\ for\ new\ entries\ is\ not\ valid=The chosen date format for new entries is not valid The\ chosen\ encoding\ '%0'\ could\ not\ encode\ the\ following\ characters\:=The chosen encoding '%0' could not encode the following characters: the\ field\ %0=the field %0 - -The\ file
'%0'
has\ been\ modified
externally\!=The file
'%0'
has been modified
externally! - The\ group\ "%0"\ already\ contains\ the\ selection.=The group "%0" already contains the selection. The\ label\ of\ the\ string\ cannot\ be\ a\ number.=The label of the string cannot be a number. @@ -1025,8 +916,6 @@ The\ label\ of\ the\ string\ cannot\ contain\ spaces.=The label of the string ca The\ label\ of\ the\ string\ cannot\ contain\ the\ '\#'\ character.=The label of the string cannot contain the '#' character. The\ output\ option\ depends\ on\ a\ valid\ import\ option.=The output option depends on a valid import option. -The\ PDF\ contains\ one\ or\ several\ BibTeX-records.=The PDF contains one or several BibTeX-records. -Do\ you\ want\ to\ import\ these\ as\ new\ entries\ into\ the\ current\ library?=Do you want to import these as new entries into the current library? The\ regular\ expression\ %0\ is\ invalid\:=The regular expression %0 is invalid: @@ -1037,9 +926,6 @@ The\ search\ is\ case\ sensitive.=The search is case sensitive. The\ string\ has\ been\ removed\ locally=The string has been removed locally There\ are\ possible\ duplicates\ (marked\ with\ an\ icon)\ that\ haven't\ been\ resolved.\ Continue?=There are possible duplicates (marked with an icon) that haven't been resolved. Continue? - -This\ entry\ has\ no\ BibTeX\ key.\ Generate\ key\ now?=This entry has no BibTeX key. Generate key now? - This\ entry\ type\ cannot\ be\ removed.=This entry type cannot be removed. This\ group\ contains\ entries\ based\ on\ manual\ assignment.\ Entries\ can\ be\ assigned\ to\ this\ group\ by\ selecting\ them\ then\ using\ either\ drag\ and\ drop\ or\ the\ context\ menu.\ Entries\ can\ be\ removed\ from\ this\ group\ by\ selecting\ them\ then\ using\ the\ context\ menu.=This group contains entries based on manual assignment. Entries can be assigned to this group by selecting them then using either drag and drop or the context menu. Entries can be removed from this group by selecting them then using the context menu. @@ -1053,7 +939,6 @@ This\ operation\ requires\ all\ selected\ entries\ to\ have\ BibTeX\ keys\ defin This\ operation\ requires\ one\ or\ more\ entries\ to\ be\ selected.=This operation requires one or more entries to be selected. This\ setting\ may\ be\ changed\ in\ preferences\ at\ any\ time.=This setting may be changed in preferences at any time. - Timezone\ (Provides\ for\ better\ recommendations\ by\ indicating\ the\ time\ of\ day\ the\ request\ is\ being\ made.)=Timezone (Provides for better recommendations by indicating the time of day the request is being made.) Toggle\ entry\ preview=Toggle entry preview @@ -1086,8 +971,6 @@ untitled=untitled Up=Up Upgrade\ external\ PDF/PS\ links\ to\ use\ the\ '%0'\ field.=Upgrade external PDF/PS links to use the '%0' field. -Upgrade\ file=Upgrade file -Upgrade\ old\ external\ file\ links\ to\ use\ the\ new\ feature=Upgrade old external file links to use the new feature usage=usage Use\ autocompletion\ for\ the\ following\ fields=Use autocompletion for the following fields @@ -1117,7 +1000,6 @@ Warnings=Warnings web\ link=web link What\ do\ you\ want\ to\ do?=What do you want to do? - Whatever\ option\ you\ choose,\ Mr.\ DLib\ may\ share\ its\ data\ with\ research\ partners\ to\ further\ improve\ recommendation\ quality\ as\ part\ of\ a\ 'living\ lab'.\ Mr.\ DLib\ may\ also\ release\ public\ datasets\ that\ may\ contain\ anonymized\ information\ about\ you\ and\ the\ recommendations\ (sensitive\ information\ such\ as\ metadata\ of\ your\ articles\ will\ be\ anonymised\ through\ e.g.\ hashing).\ Research\ partners\ are\ obliged\ to\ adhere\ to\ the\ same\ strict\ data\ protection\ policy\ as\ Mr.\ DLib.=Whatever option you choose, Mr. DLib may share its data with research partners to further improve recommendation quality as part of a 'living lab'. Mr. DLib may also release public datasets that may contain anonymized information about you and the recommendations (sensitive information such as metadata of your articles will be anonymised through e.g. hashing). Research partners are obliged to adhere to the same strict data protection policy as Mr. DLib. When\ adding/removing\ keywords,\ separate\ them\ by=When adding/removing keywords, separate them by @@ -1136,7 +1018,6 @@ Writing\ XMP-metadata\ for\ selected\ entries...=Writing XMP-metadata for select XMP-annotated\ PDF=XMP-annotated PDF XMP\ export\ privacy\ settings=XMP export privacy settings XMP-metadata=XMP-metadata -XMP-metadata\ found\ in\ PDF\:\ %0=XMP-metadata found in PDF: %0 You\ must\ restart\ JabRef\ for\ this\ to\ come\ into\ effect.=You must restart JabRef for this to come into effect. You\ have\ changed\ the\ language\ setting.=You have changed the language setting. @@ -1153,16 +1034,11 @@ Rename\ file=Rename file Move\ file\ to\ file\ directory\ and\ rename\ file=Move file to file directory and rename file -Move\ file\ failed=Move file failed Could\ not\ move\ file\ '%0'.=Could not move file '%0'. Could\ not\ find\ file\ '%0'.=Could not find file '%0'. Number\ of\ entries\ successfully\ imported=Number of entries successfully imported -Import\ canceled\ by\ user=Import canceled by user Error\ while\ fetching\ from\ %0=Error while fetching from %0 -Show\ search\ results\ in\ a\ window=Show search results in a window -Show\ global\ search\ results\ in\ a\ window=Show global search results in a window -Search\ in\ all\ open\ libraries=Search in all open libraries Refuse\ to\ save\ the\ library\ before\ external\ changes\ have\ been\ reviewed.=Refuse to save the library before external changes have been reviewed. Library\ protection=Library protection Unable\ to\ save\ library=Unable to save library @@ -1180,15 +1056,12 @@ Use\ IEEE\ LaTeX\ abbreviations=Use IEEE LaTeX abbreviations When\ opening\ file\ link,\ search\ for\ matching\ file\ if\ no\ link\ is\ defined=When opening file link, search for matching file if no link is defined Settings\ for\ %0=Settings for %0 - -Line\ %0\:\ Found\ corrupted\ BibTeX\ key.=Line %0: Found corrupted BibTeX key. -Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ (contains\ whitespaces).=Line %0: Found corrupted BibTeX key (contains whitespaces). -Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ (comma\ missing).=Line %0: Found corrupted BibTeX key (comma missing). +Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1.=Line %0: Found corrupted BibTeX key %1. +Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1\ (contains\ whitespaces).=Line %0: Found corrupted BibTeX key %1 (contains whitespaces). +Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1\ (comma\ missing).=Line %0: Found corrupted BibTeX key %1 (comma missing). No\ full\ text\ document\ found=No full text document found -Update\ to\ current\ column\ order=Update to current column order Download\ from\ URL=Download from URL Rename\ field=Rename field -Set/clear/append/rename\ fields=Set/clear/append/rename fields Append\ field=Append field Append\ to\ fields=Append to fields Rename\ field\ to=Rename field to @@ -1209,7 +1082,6 @@ Export\ entries\ in\ their\ original\ order=Export entries in their original ord Error\ opening\ file\ '%0'.=Error opening file '%0'. Formatter\ not\ found\:\ %0=Formatter not found: %0 -Clear\ inputarea=Clear inputarea Could\ not\ save,\ file\ locked\ by\ another\ JabRef\ instance.=Could not save, file locked by another JabRef instance. Current\ tmp\ value=Current tmp value @@ -1222,7 +1094,6 @@ Enforce\ legal\ characters\ in\ BibTeX\ keys=Enforce legal characters in BibTeX Unable\ to\ create\ backup=Unable to create backup Move\ file\ to\ file\ directory=Move file to file directory -Rename\ file\ to=Rename file to All\ Entries\ (this\ group\ cannot\ be\ edited\ or\ removed)=All Entries (this group cannot be edited or removed) static\ group=static group dynamic\ group=dynamic group @@ -1233,10 +1104,6 @@ search\ expression=search expression Optional\ fields\ 2=Optional fields 2 Waiting\ for\ save\ operation\ to\ finish=Waiting for save operation to finish -Resolving\ duplicate\ BibTeX\ keys...=Resolving duplicate BibTeX keys... -Finished\ resolving\ duplicate\ BibTeX\ keys.\ %0\ entries\ modified.=Finished resolving duplicate BibTeX keys. %0 entries modified. -This\ library\ contains\ one\ or\ more\ duplicated\ BibTeX\ keys.=This library contains one or more duplicated BibTeX keys. -Do\ you\ want\ to\ resolve\ duplicate\ keys\ now?=Do you want to resolve duplicate keys now? Find\ and\ remove\ duplicate\ BibTeX\ keys=Find and remove duplicate BibTeX keys Expected\ syntax\ for\ --fetch\='\:'=Expected syntax for --fetch=':' @@ -1248,18 +1115,12 @@ Ensure\ unique\ keys\ using\ letters\ (b,\ c,\ ...)=Ensure unique keys using let General\ file\ directory=General file directory User-specific\ file\ directory=User-specific file directory +LaTex\ file\ directory=LaTex file directory Search\ failed\:\ illegal\ search\ expression=Search failed: illegal search expression Show\ ArXiv\ column=Show ArXiv column You\ must\ enter\ an\ integer\ value\ in\ the\ interval\ 1025-65535\ in\ the\ text\ field\ for=You must enter an integer value in the interval 1025-65535 in the text field for Automatically\ open\ browse\ dialog\ when\ creating\ new\ file\ link=Automatically open browse dialog when creating new file link -Import\ metadata\ from\:=Import metadata from: -Choose\ the\ source\ for\ the\ metadata\ import=Choose the source for the metadata import -Create\ entry\ based\ on\ XMP-metadata=Create entry based on XMP-metadata -Create\ blank\ entry\ linking\ the\ PDF=Create blank entry linking the PDF -Only\ attach\ PDF=Only attach PDF -Create\ new\ entry=Create new entry -Update\ existing\ entry=Update existing entry Autocomplete\ names\ in\ 'Firstname\ Lastname'\ format\ only=Autocomplete names in 'Firstname Lastname' format only Autocomplete\ names\ in\ 'Lastname,\ Firstname'\ format\ only=Autocomplete names in 'Lastname, Firstname' format only Autocomplete\ names\ in\ both\ formats=Autocomplete names in both formats @@ -1269,9 +1130,6 @@ References=References Sending\ of\ emails=Sending of emails Subject\ for\ sending\ an\ email\ with\ references=Subject for sending an email with references Automatically\ open\ folders\ of\ attached\ files=Automatically open folders of attached files -Create\ entry\ based\ on\ content=Create entry based on content -Do\ not\ show\ this\ box\ again\ for\ this\ import=Do not show this box again for this import -Always\ use\ this\ PDF\ import\ style\ (and\ do\ not\ ask\ for\ each\ import)=Always use this PDF import style (and do not ask for each import) Error\ creating\ email=Error creating email Entries\ added\ to\ an\ email=Entries added to an email exportFormat=exportFormat @@ -1336,10 +1194,8 @@ No\ valid\ style\ file\ defined=No valid style file defined Choose\ pattern=Choose pattern Use\ the\ BIB\ file\ location\ as\ primary\ file\ directory=Use the BIB file location as primary file directory Could\ not\ run\ the\ gnuclient/emacsclient\ program.\ Make\ sure\ you\ have\ the\ emacsclient/gnuclient\ program\ installed\ and\ available\ in\ the\ PATH.=Could not run the gnuclient/emacsclient program. Make sure you have the emacsclient/gnuclient program installed and available in the PATH. -OpenOffice/LibreOffice\ connection=OpenOffice/LibreOffice connection You\ must\ select\ either\ a\ valid\ style\ file,\ or\ use\ one\ of\ the\ default\ styles.=You must select either a valid style file, or use one of the default styles. -This\ is\ a\ simple\ copy\ and\ paste\ dialog.\ First\ load\ or\ paste\ some\ text\ into\ the\ text\ input\ area.
After\ that,\ you\ can\ mark\ text\ and\ assign\ it\ to\ a\ BibTeX\ field.=This is a simple copy and paste dialog. First load or paste some text into the text input area.
After that, you can mark text and assign it to a BibTeX field. This\ feature\ generates\ a\ new\ library\ based\ on\ which\ entries\ are\ needed\ in\ an\ existing\ LaTeX\ document.=This feature generates a new library based on which entries are needed in an existing LaTeX document. First\ select\ entries\ to\ clean\ up.=First select entries to clean up. @@ -1383,19 +1239,14 @@ Opens\ the\ file\ browser.=Opens the file browser. Scan\ directory=Scan directory Searches\ the\ selected\ directory\ for\ unlinked\ files.=Searches the selected directory for unlinked files. Starts\ the\ import\ of\ BibTeX\ entries.=Starts the import of BibTeX entries. -Create\ directory\ based\ keywords=Create directory based keywords -Creates\ keywords\ in\ created\ entrys\ with\ directory\ pathnames=Creates keywords in created entrys with directory pathnames Select\ a\ directory\ where\ the\ search\ shall\ start.=Select a directory where the search shall start. Select\ file\ type\:=Select file type: These\ files\ are\ not\ linked\ in\ the\ active\ library.=These files are not linked in the active library. -Entry\ type\ to\ be\ created\:=Entry type to be created: Searching\ file\ system...=Searching file system... Select\ directory=Select directory Select\ files=Select files BibTeX\ entry\ creation=BibTeX entry creation Unable\ to\ connect\ to\ FreeCite\ online\ service.=Unable to connect to FreeCite online service. -Parse\ with\ FreeCite=Parse with FreeCite -How\ would\ you\ like\ to\ link\ to\ '%0'?=How would you like to link to '%0'? BibTeX\ key\ patterns=BibTeX key patterns Changed\ special\ field\ settings=Changed special field settings Clear\ priority=Clear priority @@ -1434,7 +1285,6 @@ Toggle\ print\ status=Toggle print status Update\ keywords=Update keywords Write\ values\ of\ special\ fields\ as\ separate\ fields\ to\ BibTeX=Write values of special fields as separate fields to BibTeX You\ have\ changed\ settings\ for\ special\ fields.=You have changed settings for special fields. -A\ string\ with\ that\ label\ already\ exists=A string with that label already exists Connection\ to\ OpenOffice/LibreOffice\ has\ been\ lost.\ Please\ make\ sure\ OpenOffice/LibreOffice\ is\ running,\ and\ try\ to\ reconnect.=Connection to OpenOffice/LibreOffice has been lost. Please make sure OpenOffice/LibreOffice is running, and try to reconnect. JabRef\ will\ send\ at\ least\ one\ request\ per\ entry\ to\ a\ publisher.=JabRef will send at least one request per entry to a publisher. Correct\ the\ entry,\ and\ reopen\ editor\ to\ display/edit\ source.=Correct the entry, and reopen editor to display/edit source. @@ -1443,7 +1293,6 @@ Make\ sure\ you\ have\ installed\ OpenOffice/LibreOffice\ with\ Java\ support.=M If\ connecting\ manually,\ please\ verify\ program\ and\ library\ paths.=If connecting manually, please verify program and library paths. Error\ message\:=Error message: If\ a\ pasted\ or\ imported\ entry\ already\ has\ the\ field\ set,\ overwrite.=If a pasted or imported entry already has the field set, overwrite. -Import\ metadata\ from\ PDF=Import metadata from PDF Not\ connected\ to\ any\ Writer\ document.\ Please\ make\ sure\ a\ document\ is\ open,\ and\ use\ the\ 'Select\ Writer\ document'\ button\ to\ connect\ to\ it.=Not connected to any Writer document. Please make sure a document is open, and use the 'Select Writer document' button to connect to it. Removed\ all\ subgroups\ of\ group\ "%0".=Removed all subgroups of group "%0". To\ disable\ the\ memory\ stick\ mode\ rename\ or\ remove\ the\ jabref.xml\ file\ in\ the\ same\ folder\ as\ JabRef.=To disable the memory stick mode rename or remove the jabref.xml file in the same folder as JabRef. @@ -1492,23 +1341,19 @@ Rebind\ C-a,\ too=Rebind C-a, too Rebind\ C-f,\ too=Rebind C-f, too Open\ folder=Open folder -Searches\ for\ unlinked\ PDF\ files\ on\ the\ file\ system=Searches for unlinked PDF files on the file system Export\ entries\ ordered\ as\ specified=Export entries ordered as specified Export\ sort\ order=Export sort order Export\ sorting=Export sorting Newline\ separator=Newline separator +Save\ in\ current\ table\ sort\ order=Save in current table sort order Save\ entries\ ordered\ as\ specified=Save entries ordered as specified -Save\ sort\ order=Save sort order Show\ extra\ columns=Show extra columns Parsing\ error=Parsing error illegal\ backslash\ expression=illegal backslash expression -Move\ to\ group=Move to group - Clear\ read\ status=Clear read status Convert\ to\ biblatex\ format\ (for\ example,\ move\ the\ value\ of\ the\ 'journal'\ field\ to\ 'journaltitle')=Convert to biblatex format (for example, move the value of the 'journal' field to 'journaltitle') -Could\ not\ apply\ changes.=Could not apply changes. Deprecated\ fields=Deprecated fields No\ read\ status\ information=No read status information Printed=Printed @@ -1562,13 +1407,10 @@ Removed\ all\ groups=Removed all groups Accepting\ the\ change\ replaces\ the\ complete\ groups\ tree\ with\ the\ externally\ modified\ groups\ tree.=Accepting the change replaces the complete groups tree with the externally modified groups tree. Select\ export\ format=Select export format Return\ to\ JabRef=Return to JabRef -Please\ move\ the\ file\ manually\ and\ link\ in\ place.=Please move the file manually and link in place. Could\ not\ connect\ to\ %0=Could not connect to %0 Warning\:\ %0\ out\ of\ %1\ entries\ have\ undefined\ title.=Warning: %0 out of %1 entries have undefined title. Warning\:\ %0\ out\ of\ %1\ entries\ have\ undefined\ BibTeX\ key.=Warning: %0 out of %1 entries have undefined BibTeX key. Added\ new\ '%0'\ entry.=Added new '%0' entry. -Multiple\ entries\ selected.\ Do\ you\ want\ to\ change\ the\ type\ of\ all\ these\ to\ '%0'?=Multiple entries selected. Do you want to change the type of all these to '%0'? -Changed\ type\ to\ '%0'\ for=Changed type to '%0' for Really\ delete\ the\ selected\ entry?=Really delete the selected entry? Really\ delete\ the\ %0\ selected\ entries?=Really delete the %0 selected entries? Keep\ merged\ entry\ only=Keep merged entry only @@ -1592,13 +1434,7 @@ unexpected\ opening\ curly\ bracket=unexpected opening curly bracket capital\ letters\ are\ not\ masked\ using\ curly\ brackets\ {}=capital letters are not masked using curly brackets {} should\ contain\ a\ four\ digit\ number=should contain a four digit number should\ contain\ a\ valid\ page\ number\ range=should contain a valid page number range -Filled=Filled -Field\ is\ missing=Field is missing Search\ %0=Search %0 - -Search\ results\ in\ all\ libraries\ for\ %0=Search results in all libraries for %0 -Search\ results\ in\ library\ %0\ for\ %1=Search results in library %0 for %1 -Search\ globally=Search globally No\ results\ found.=No results found. Found\ %0\ results.=Found %0 results. plain\ text=plain text @@ -1607,8 +1443,6 @@ This\ search\ contains\ entries\ in\ which\ any\ field\ contains\ the\ term\ This\ search\ contains\ entries\ in\ which=This search contains entries in which Unable\ to\ autodetect\ OpenOffice/LibreOffice\ installation.\ Please\ choose\ the\ installation\ directory\ manually.=Unable to autodetect OpenOffice/LibreOffice installation. Please choose the installation directory manually. -JabRef\ no\ longer\ supports\ 'ps'\ or\ 'pdf'\ fields.
File\ links\ are\ now\ stored\ in\ the\ 'file'\ field\ and\ files\ are\ stored\ in\ an\ external\ file\ directory.
To\ make\ use\ of\ this\ feature,\ JabRef\ needs\ to\ upgrade\ file\ links.

=JabRef no longer supports 'ps' or 'pdf' fields.
File links are now stored in the 'file' field and files are stored in an external file directory.
To make use of this feature, JabRef needs to upgrade file links.

-This\ library\ uses\ outdated\ file\ links.=This library uses outdated file links. Close\ library=Close library Decrease\ table\ font\ size=Decrease table font size @@ -1816,9 +1650,6 @@ License=License HTML\ encoded\ character\ found=HTML encoded character found booktitle\ ends\ with\ 'conference\ on'=booktitle ends with 'conference on' -All\ external\ files=All external files - - incorrect\ control\ digit=incorrect control digit incorrect\ format=incorrect format Copied\ version\ to\ clipboard=Copied version to clipboard @@ -1858,7 +1689,6 @@ Open\ console=Open console Use\ default\ terminal\ emulator=Use default terminal emulator Execute\ command=Execute command Note\:\ Use\ the\ placeholder\ %0\ for\ the\ location\ of\ the\ opened\ library\ file.=Note: Use the placeholder %0 for the location of the opened library file. -Executing\ command\ \"%0\"...=Executing command \"%0\"... Error\ occured\ while\ executing\ the\ command\ \"%0\".=Error occured while executing the command \"%0\". Reformat\ ISSN=Reformat ISSN @@ -1961,9 +1791,6 @@ Non-ASCII\ encoded\ character\ found=Non-ASCII encoded character found Toggle\ web\ search\ interface=Toggle web search interface %0\ files\ found=%0 files found One\ file\ found=One file found -The\ import\ finished\ with\ warnings\:=The import finished with warnings: -There\ was\ one\ file\ that\ could\ not\ be\ imported.=There was one file that could not be imported. -There\ were\ %0\ files\ which\ could\ not\ be\ imported.=There were %0 files which could not be imported. Migration\ help\ information=Migration help information Entered\ database\ has\ obsolete\ structure\ and\ is\ no\ longer\ supported.=Entered database has obsolete structure and is no longer supported. @@ -1986,6 +1813,7 @@ Sumatra\ Reader=Sumatra Reader shared=shared should\ contain\ an\ integer\ or\ a\ literal=should contain an integer or a literal should\ have\ the\ first\ letter\ capitalized=should have the first letter capitalized +edition\ of\ book\ reported\ as\ just\ 1=edition of book reported as just 1 Tools=Tools What\'s\ new\ in\ this\ version?=What\'s new in this version? Want\ to\ help?=Want to help? @@ -2059,7 +1887,6 @@ Next\ page=Next page Document\ viewer=Document viewer Live=Live Locked=Locked -Show\ document\ viewer=Show document viewer Show\ the\ document\ of\ the\ currently\ selected\ entry.=Show the document of the currently selected entry. Show\ this\ document\ until\ unlocked.=Show this document until unlocked. Set\ current\ user\ name\ as\ owner.=Set current user name as owner. @@ -2116,8 +1943,6 @@ No\ linked\ files\ found\ for\ export.=No linked files found for export. No\ full\ text\ document\ found\ for\ entry\ %0.=No full text document found for entry %0. Delete\ Entry=Delete Entry -Import\ &\ Export=Import & Export -Look\ up\ document\ identifier=Look up document identifier Next\ library=Next library Previous\ library=Previous library add\ group=add group @@ -2128,8 +1953,6 @@ Keep\ entry=Keep entry Ignore\ backup=Ignore backup Restore\ from\ backup=Restore from backup -Continue=Continue -Generate\ key=Generate key Overwrite\ file=Overwrite file Shared\ database\ connection=Shared database connection @@ -2157,8 +1980,6 @@ Toggle\ intersection=Toggle intersection Toggle\ union=Toggle union Jump\ to\ entry=Jump to entry The\ group\ name\ contains\ the\ keyword\ separator\ "%0"\ and\ thus\ probably\ does\ not\ work\ as\ expected.=The group name contains the keyword separator "%0" and thus probably does not work as expected. -Abbreviate\ journal\ names\ (ISO)=Abbreviate journal names (ISO) -Abbreviate\ journal\ names\ (MEDLINE)=Abbreviate journal names (MEDLINE) Blog=Blog Check\ integrity=Check integrity Cleanup\ URL\ link=Cleanup URL link @@ -2184,7 +2005,6 @@ View\ change\ log=View change log View\ event\ log=View event log Website=Website Write\ XMP-metadata\ to\ PDFs=Write XMP-metadata to PDFs -Do\ you\ want\ to\ import\ these\ as\ new\ entries\ into\ the\ current\ library\ or\ do\ you\ want\ to\ link\ the\ file\ to\ the\ entry?=Do you want to import these as new entries into the current library or do you want to link the file to the entry? Font\ size\:=Font size\: Override\ default\ font\ settings=Override default font settings @@ -2214,5 +2034,62 @@ Main\ layout\ file=Main layout file Save\ exporter=Save exporter File\ extension\:=File extension\: Export\ format\ name\:=Export format name\: - Cleared\ connection\ settings=Cleared connection settings +Error\ adding\ discovered\ CitationStyles=Error adding discovered CitationStyles +(more)=(more) +Cancel\ import=Cancel import +Continue\ with\ import=Continue with import +Import\ canceled=Import canceled +Select\ all\ new\ entries=Select all new entries +Select\ the\ entries\ to\ be\ imported\:=Select the entries to be imported\: +Add\ new\ String=Add new String +Remove\ selected\ Strings=Remove selected Strings +Must\ not\ be\ empty\!=Must not be empty\! +Open\ Help\ page=Open Help page +Active\ database\ connection\ do\ not\ exists\!=Active database connection do not exists! +Add\ new\ field\ name=Add new field name +Field\ name\:=Field name: +Field\ name\ \"%0\"\ already\ exists=Field name "%0" already exists +No\ field\ name\ selected\!=No field name selected! +Remove\ field\ name=Remove field name +Are\ you\ sure\ you\ want\ to\ remove\ field\ name\:\ \"%0\"?=Are you sure you want to remove field name: "%0"? +Add\ new\ keyword=Add new keyword +Keyword\:=Keyword: +Keyword\ \"%0\"\ already\ exists=Keyword "%0" already exists +Remove\ keyword=Remove keyword +Are\ you\ sure\ you\ want\ to\ remove\ keyword\:\ \"%0\"?=Are you sure you want to remove keyword: "%0"? +Reset\ to\ default=Reset to default +Edit\ string\ constants=Edit string constants +Export\ all\ entries=Export all entries +Generate\ BibTeX\ keys=Generate BibTeX keys +Groups\ interface=Groups interface +Manage\ field\ names\ &\ content=Manage field names & content +New\ library=New library +Next\ citation\ style=Next citation style +OpenOffice/LibreOffice=OpenOffice/LibreOffice +Open\ document\ viewer=Open document viewer +Open\ entry\ editor=Open entry editor +Previous\ citation\ style=Previous citation style +Search\ document\ identifier\ online=Search document identifier online +Search\ for\ unlinked\ local\ files=Search for unlinked local files +Search\ full\ text\ documents\ online=Search full text documents online +Find\ and\ replace=Find and replace + +Found\ documents\:=Found documents\: +Use\ selected\ document=Use selected document +Accept\ changes=Accept changes +Dismiss\ changes=Dismiss changes +The\ library\ has\ been\ modified\ by\ another\ program.=The library has been modified by another program. + +Browser=Browser +Execute\ Command=Execute Command +Open\ File\ Browser=Open File Browser +Use\ default\ file\ browser=Use default file browser + +Set\ rank\ to\ one=Set rank to one +Set\ rank\ to\ two=Set rank to two +Set\ rank\ to\ three=Set rank to three +Set\ rank\ to\ four=Set rank to four +Set\ rank\ to\ five=Set rank to five + +Executing\ command\ "%0"...=Executing command "%0"... \ No newline at end of file diff --git a/src/test/java/org/jabref/architecture/TestArchitectureTests.java b/src/test/java/org/jabref/architecture/TestArchitectureTests.java index da908308d9d..e7fe93d14fe 100644 --- a/src/test/java/org/jabref/architecture/TestArchitectureTests.java +++ b/src/test/java/org/jabref/architecture/TestArchitectureTests.java @@ -41,7 +41,6 @@ public TestArchitectureTests() { exceptions.add(CLASS_ORG_JABREF_UPDATE_TIMESTAMP_LISTENER_TEST); exceptions.add(CLASS_ORG_JABREF_ENTRY_EDITOR_TEST); exceptions.add(CLASS_ORG_JABREF_LINKED_FILE_VIEW_MODEL_TEST); - } public static Stream data() { diff --git a/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java b/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java deleted file mode 100644 index b44b0c572aa..00000000000 --- a/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.jabref.cleanup; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; - -import org.jabref.gui.cleanup.CleanupActionsListModel; -import org.jabref.logic.cleanup.Cleanups; -import org.jabref.logic.formatter.bibtexfields.ClearFormatter; -import org.jabref.model.cleanup.FieldFormatterCleanup; -import org.jabref.model.cleanup.FieldFormatterCleanups; - -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class CleanupActionsListModelTest { - - @Test - public void resetFiresItemsChanged() throws Exception { - CleanupActionsListModel model = new CleanupActionsListModel(Collections.emptyList()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - FieldFormatterCleanups defaultFormatters = mock(FieldFormatterCleanups.class); - - model.reset(defaultFormatters); - - ArgumentCaptor argument = ArgumentCaptor.forClass(ListDataEvent.class); - verify(listener).contentsChanged(argument.capture()); - assertEquals(ListDataEvent.CONTENTS_CHANGED, argument.getValue().getType()); - } - - @Test - public void resetSetsFormattersToPassedList() throws Exception { - CleanupActionsListModel model = new CleanupActionsListModel(Collections.emptyList()); - FieldFormatterCleanups defaultFormatters = mock(FieldFormatterCleanups.class); - List formatters = Arrays.asList(new FieldFormatterCleanup("test", new ClearFormatter())); - when(defaultFormatters.getConfiguredActions()).thenReturn(formatters); - - model.reset(defaultFormatters); - - assertEquals(formatters, model.getAllActions()); - } - - public List getDefaultFieldFormatterCleanups() { - FieldFormatterCleanups formatters = Cleanups.DEFAULT_SAVE_ACTIONS; - //new ArrayList because configured actions is an unmodifiable collection - return new ArrayList<>(formatters.getConfiguredActions()); - } - - @Test - public void removedAtIndexOkay() { - - CleanupActionsListModel model = new CleanupActionsListModel(getDefaultFieldFormatterCleanups()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - model.removeAtIndex(0); - - ArgumentCaptor argument = ArgumentCaptor.forClass(ListDataEvent.class); - verify(listener).intervalRemoved(argument.capture()); - assertEquals(ListDataEvent.INTERVAL_REMOVED, argument.getValue().getType()); - } - - @Test - public void removedAtIndexMinus1DoesNothing() { - - CleanupActionsListModel model = new CleanupActionsListModel(getDefaultFieldFormatterCleanups()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - model.removeAtIndex(-1); - - verifyZeroInteractions(listener); - } - - @Test - public void removedAtIndexgreaterListSizeDoesNothing() { - - CleanupActionsListModel model = new CleanupActionsListModel(getDefaultFieldFormatterCleanups()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - model.removeAtIndex((getDefaultFieldFormatterCleanups().size() + 1)); - - verifyZeroInteractions(listener); - } -} diff --git a/src/test/java/org/jabref/gui/AWTExceptionHandler.java b/src/test/java/org/jabref/gui/AWTExceptionHandler.java deleted file mode 100644 index 74586f4d709..00000000000 --- a/src/test/java/org/jabref/gui/AWTExceptionHandler.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.jabref.gui; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.swing.SwingUtilities; - -/** - * Can catch any exceptions occurring on the EDT thread for assertion. - */ -public class AWTExceptionHandler { - - private final List list = new CopyOnWriteArrayList<>(); - - public void installExceptionDetectionInEDT() { - SwingUtilities.invokeLater(() -> Thread.currentThread().setUncaughtExceptionHandler((t, e) -> list.add(e))); - } - - public void assertNoExceptions() { - if (!list.isEmpty()) { - throw new AssertionError("Uncaught exception in EDT", list.get(0)); - } - } -} diff --git a/src/test/java/org/jabref/gui/AbstractUITest.java b/src/test/java/org/jabref/gui/AbstractUITest.java deleted file mode 100644 index dfc33236d98..00000000000 --- a/src/test/java/org/jabref/gui/AbstractUITest.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.jabref.gui; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.jabref.JabRefMain; - -import org.assertj.swing.fixture.AbstractWindowFixture; -import org.assertj.swing.fixture.FrameFixture; -import org.assertj.swing.fixture.JFileChooserFixture; -import org.assertj.swing.fixture.JTableFixture; -import org.assertj.swing.image.ScreenshotTaker; -import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase; -import org.assertj.swing.timing.Pause; -import org.junit.jupiter.api.Tag; - -import static org.assertj.swing.launcher.ApplicationLauncher.application; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Tag("GUITest") -public abstract class AbstractUITest extends AssertJSwingJUnitTestCase { - - protected final static int SPEED_NORMAL = 50; - - protected AWTExceptionHandler awtExceptionHandler; - protected FrameFixture mainFrame; - - @Override - protected void onSetUp() { - awtExceptionHandler = new AWTExceptionHandler(); - awtExceptionHandler.installExceptionDetectionInEDT(); - application(JabRefMain.class).start(); - - robot().waitForIdle(); - - robot().settings().timeoutToFindSubMenu(1_000); - robot().settings().delayBetweenEvents(SPEED_NORMAL); - - //mainFrame = findFrame(null).withTimeout(10_000).using(robot()); - robot().waitForIdle(); - } - - /** - * Returns the absolute Path of the given relative Path The backlashes are replaced with forwardslashes b/c assertJ - * can't type the former one on windows - * - * @param relativePath the relative path to the resource database - */ - protected String getAbsolutePath(String relativePath) throws URISyntaxException { - final URL resource = this.getClass().getClassLoader().getResource(relativePath); - return Paths.get(resource.toURI()).toAbsolutePath().toString().replace("\\", "/"); - } - - /** - * opens a database and gives JabRef a second to open it before proceeding - */ - protected void importBibIntoNewDatabase(String path) { - mainFrame.menuItemWithPath("File", "Import into new library").click(); - JFileChooserFixture openFileDialog = mainFrame.fileChooser(); - robot().settings().delayBetweenEvents(1); - openFileDialog.fileNameTextBox().enterText(path); - openFileDialog.approve(); - Pause.pause(1_000); - } - - protected void exitJabRef() { - mainFrame.menuItemWithPath("File", "Quit").click(); - awtExceptionHandler.assertNoExceptions(); - } - - protected void newDatabase() { - mainFrame.menuItemWithPath("File", "New BibTeX database").click(); - } - - protected void closeDatabase() { - mainFrame.menuItemWithPath("File", "Close library").click(); - } - - protected void takeScreenshot(AbstractWindowFixture dialog, String filename) throws IOException { - ScreenshotTaker screenshotTaker = new ScreenshotTaker(); - Path folder = Paths.get("build", "screenshots"); - // Create build/srceenshots folder if not present - if (!Files.exists(folder)) { - Files.createDirectory(folder); - } - Path file = folder.resolve(filename + ".png").toAbsolutePath(); - // Delete already present file - if (Files.exists(file)) { - Files.delete(file); - } - screenshotTaker.saveComponentAsPng(dialog.target(), file.toString()); - } - - protected void assertColumnValue(JTableFixture table, int rowIndex, int columnIndex, String selectionValue) { - String[][] tableContent; - tableContent = table.contents(); - - String value = tableContent[rowIndex][columnIndex]; - assertEquals(value, selectionValue); - } -} diff --git a/src/test/java/org/jabref/gui/DialogTest.java b/src/test/java/org/jabref/gui/DialogTest.java deleted file mode 100644 index e97eb1a56dc..00000000000 --- a/src/test/java/org/jabref/gui/DialogTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.jabref.gui; - -import javax.swing.JButton; -import javax.swing.JDialog; - -import org.assertj.swing.core.GenericTypeMatcher; -import org.assertj.swing.dependency.jsr305.Nonnull; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; - -import static org.assertj.swing.finder.WindowFinder.findDialog; - -/** - * This test has been split to work, the other part can be found at DialogTest2 - */ -@Tag("GUITest") -public class DialogTest extends AbstractUITest { - - @Test - public void testCancelStyleSelectDialog() { - mainFrame.menuItemWithPath("Tools", "OpenOffice/LibreOffice connection").click(); - - GenericTypeMatcher buttonMatcher = new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Select style".equals(jButton.getText()); - } - }; - - mainFrame.button(buttonMatcher).click(); - - GenericTypeMatcher styleDialogMatcher = new GenericTypeMatcher(JDialog.class) { - - @Override - protected boolean isMatching(JDialog dialog) { - return "Select style".equals(dialog.getTitle()); // Only a single SidePane - } - }; - - GenericTypeMatcher buttonMatcher2 = new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Cancel".equals(jButton.getText()); - } - }; - findDialog(styleDialogMatcher).withTimeout(10_000).using(robot()).button(buttonMatcher2).click(); - exitJabRef(); - } -} diff --git a/src/test/java/org/jabref/gui/DialogTest2.java b/src/test/java/org/jabref/gui/DialogTest2.java deleted file mode 100644 index 652532dd9bb..00000000000 --- a/src/test/java/org/jabref/gui/DialogTest2.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.jabref.gui; - -import javax.swing.JButton; -import javax.swing.JDialog; - -import org.assertj.swing.core.GenericTypeMatcher; -import org.assertj.swing.dependency.jsr305.Nonnull; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; - -import static org.assertj.swing.finder.WindowFinder.findDialog; - -/** - * Split of DialogTest, since the test cases were only running separately - */ -@Tag("GUITest") -public class DialogTest2 extends AbstractUITest { - @Test - public void testCloseStyleSelectDialog() { - mainFrame.menuItemWithPath("Tools", "OpenOffice/LibreOffice connection").click(); - - GenericTypeMatcher buttonMatcher = new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Select style".equals(jButton.getText()); - } - }; - - mainFrame.button(buttonMatcher).click(); - - GenericTypeMatcher styleDialogMatcher = new GenericTypeMatcher(JDialog.class) { - - @Override - protected boolean isMatching(JDialog dialog) { - return "Select style".equals(dialog.getTitle()); // Only a single SidePane - } - }; - - findDialog(styleDialogMatcher).withTimeout(10_000).using(robot()).close(); - exitJabRef(); - } -} diff --git a/src/test/java/org/jabref/gui/EntryTableTest.java b/src/test/java/org/jabref/gui/EntryTableTest.java deleted file mode 100644 index d5f4fbfa861..00000000000 --- a/src/test/java/org/jabref/gui/EntryTableTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.jabref.gui; - -import java.awt.event.KeyEvent; -import java.util.regex.Pattern; - -import org.assertj.swing.fixture.JTableCellFixture; -import org.assertj.swing.fixture.JTableFixture; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -/** - * Specific Use-Case: I import a database. Then I doubleclick on the first entry in the table to open the entry editor. - * Then I click on the first entry again, and scroll through all of the lists entries, without having to click on the - * table again. - */ -@Tag("GUITest") -public class EntryTableTest extends AbstractUITest { - - private final static int SCROLL_ACTION_EXECUTION = 5; - private final static String TEST_FILE_NAME = "testbib/testjabref.bib"; - private final static int DOWN = KeyEvent.VK_DOWN; - private final static int UP = KeyEvent.VK_UP; - private final static int TITLE_COLUMN_INDEX = 5; - - @Test - public void scrollThroughEntryList() throws Exception { - String path = getAbsolutePath(TEST_FILE_NAME); - - importBibIntoNewDatabase(path); - - JTableFixture entryTable = mainFrame.table(); - - //use a pattern from the first row to select it since it seems to be the best way to get the cell object - Pattern pattern = Pattern.compile("256.*"); - JTableCellFixture firstCell = entryTable.cell(pattern); - - entryTable.selectRows(0).doubleClick(); - //delay has to be shortened so that double click is recognized - robot().settings().delayBetweenEvents(0); - firstCell.doubleClick(); - robot().settings().delayBetweenEvents(SPEED_NORMAL); - - firstCell.click(); - //is the first table entry selected? - assertColumnValue(entryTable, 0, TITLE_COLUMN_INDEX, entryTable.selectionValue()); - - //go throught the table and check if the entry with the correct index is selected - for (int i = 0; i < SCROLL_ACTION_EXECUTION; i++) { - robot().pressAndReleaseKey(DOWN); - assertNotNull(entryTable.selectionValue()); - assertColumnValue(entryTable, i + 1, TITLE_COLUMN_INDEX, entryTable.selectionValue()); - } - //do the same going up again - for (int i = SCROLL_ACTION_EXECUTION; i > 0; i--) { - robot().pressAndReleaseKey(UP); - assertNotNull(entryTable.selectionValue()); - assertColumnValue(entryTable, i - 1, TITLE_COLUMN_INDEX, entryTable.selectionValue()); - } - - closeDatabase(); - exitJabRef(); - } -} diff --git a/src/test/java/org/jabref/gui/IdFetcherDialogTest.java b/src/test/java/org/jabref/gui/IdFetcherDialogTest.java deleted file mode 100644 index 65a1330b25a..00000000000 --- a/src/test/java/org/jabref/gui/IdFetcherDialogTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.jabref.gui; - -import java.util.stream.Stream; - -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.text.JTextComponent; - -import org.assertj.swing.core.GenericTypeMatcher; -import org.assertj.swing.dependency.jsr305.Nonnull; -import org.assertj.swing.fixture.JTableFixture; -import org.assertj.swing.timing.Condition; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.assertj.swing.finder.WindowFinder.findDialog; -import static org.assertj.swing.timing.Pause.pause; - -@Tag("GUITest") -public class IdFetcherDialogTest extends AbstractUITest { - - @ParameterizedTest - @MethodSource("instancesToTest") - public void insertEmptySearchID(String databaseMode, String fetcherType, String fetchID) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry...").click(); - - GenericTypeMatcher matcher = new GenericTypeMatcher(JDialog.class) { - @Override - protected boolean isMatching(JDialog dialog) { - return "Select entry type".equals(dialog.getTitle()); - } - }; - - findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Generate".equals(jButton.getText()); - } - }).click(); - - GenericTypeMatcher matcherEmptyDialog = new GenericTypeMatcher(JDialog.class) { - @Override - protected boolean isMatching(JDialog dialog) { - return "Empty search ID".equals(dialog.getTitle()); - } - }; - - findDialog(matcherEmptyDialog).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "OK".equals(jButton.getText()); - } - }).click(); - - entryTable.requireRowCount(0); - } - - @ParameterizedTest - @MethodSource("instancesToTest") - public void testFetcherDialog(String databaseMode, String fetcherType, String fetchID) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry...").click(); - - GenericTypeMatcher matcher = new GenericTypeMatcher(JDialog.class) { - @Override - protected boolean isMatching(JDialog dialog) { - return "Select entry type".equals(dialog.getTitle()); - } - }; - - findDialog(matcher).withTimeout(10_000).using(robot()).comboBox(new GenericTypeMatcher(JComboBox.class) { - @Override - protected boolean isMatching(@Nonnull JComboBox component) { - return true; - } - }).selectItem(fetcherType); - - findDialog(matcher).withTimeout(10_000).using(robot()).textBox(new GenericTypeMatcher(JTextComponent.class) { - @Override - protected boolean isMatching(@Nonnull JTextComponent component) { - return true; - } - }).enterText(fetchID); - - findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher(JButton.class) { - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Generate".equals(jButton.getText()); - } - }).click(); - - pause(new Condition("entrySize") { - @Override - public boolean test() { - return entryTable.rowCount() == 1; - } - }, 10_000); - - entryTable.requireRowCount(1); - } - - public static Stream instancesToTest() { - return Stream.of( - new Object[]{"BibTeX", "DOI", "10.1002/9781118257517"}, - new Object[]{"biblatex", "DOI", "10.1002/9781118257517"}, - new Object[]{"BibTeX", "ISBN", "9780321356680"}, - new Object[]{"biblatex", "ISBN", "9780321356680"} - ); - } -} diff --git a/src/test/java/org/jabref/gui/ParameterizedDialogNewEntryTest.java b/src/test/java/org/jabref/gui/ParameterizedDialogNewEntryTest.java deleted file mode 100644 index 2cfd70baa8a..00000000000 --- a/src/test/java/org/jabref/gui/ParameterizedDialogNewEntryTest.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.jabref.gui; - -import java.util.Locale; -import java.util.stream.Stream; - -import javax.swing.JButton; -import javax.swing.JDialog; - -import org.assertj.swing.core.GenericTypeMatcher; -import org.assertj.swing.dependency.jsr305.Nonnull; -import org.assertj.swing.fixture.JTableFixture; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.assertj.swing.finder.WindowFinder.findDialog; - -@Tag("GUITest") -public class ParameterizedDialogNewEntryTest extends AbstractUITest { - - @ParameterizedTest - @MethodSource("instancesToTest") - public void addEntryOfGivenType(String databaseMode, String entryType) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry...").click(); - - selectEntryType(entryType); - - entryTable.requireRowCount(1); - } - - private void selectEntryType(String entryType) { - GenericTypeMatcher matcher = new GenericTypeMatcher(JDialog.class) { - - @Override - protected boolean isMatching(JDialog dialog) { - return "Select entry type".equals(dialog.getTitle()); - } - }; - - findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return entryType.equals(jButton.getText()); - } - }).click(); - } - - @ParameterizedTest - @MethodSource("instancesToTest") - public void addEntryPlainTextOfGivenType(String databaseMode, String entryType) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click(); - - selectEntryType(entryType); - - GenericTypeMatcher matcher2 = plainTextMatcher(entryType); - - findDialog(matcher2).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Accept".equals(jButton.getText()); - } - }).click(); - - entryTable.requireRowCount(1); - } - - @ParameterizedTest - @MethodSource("instancesToTest") - public void closeAddingEntryPlainTextOfGivenType(String databaseMode, String entryType) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click(); - - selectEntryType(entryType); - - GenericTypeMatcher matcher2 = plainTextMatcher(entryType); - - findDialog(matcher2).withTimeout(10_000).using(robot()).close(); - entryTable.requireRowCount(0); - } - - @ParameterizedTest - @MethodSource("instancesToTest") - public void cancelAddingEntryPlainTextOfGivenType(String databaseMode, String entryType) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click(); - - selectEntryType(entryType); - - GenericTypeMatcher matcher2 = plainTextMatcher(entryType); - - findDialog(matcher2).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return "Cancel".equals(jButton.getText()); - } - }).click(); - - entryTable.requireRowCount(0); - } - - private GenericTypeMatcher plainTextMatcher(String entryType) { - GenericTypeMatcher matcher2 = new GenericTypeMatcher(JDialog.class) { - - @Override - protected boolean isMatching(JDialog dialog) { - return ("Plain text import for " + entryType.toLowerCase(Locale.ENGLISH)).equals(dialog.getTitle()); - } - }; - return matcher2; - } - - public static Stream instancesToTest() { - // Create entry from menu - // Structure: - // {"BibTeX"/"biblatex", "type"} - // @formatter:off - return Stream.of( - new Object[]{"BibTeX", "Article"}, -/* new Object[]{"BibTeX", "InBook"}, - new Object[]{"BibTeX", "Book"}, - new Object[]{"BibTeX", "Booklet"}, - new Object[]{"BibTeX", "InCollection"}, - new Object[]{"BibTeX", "Conference"}, - new Object[]{"BibTeX", "InProceedings"}, - new Object[]{"BibTeX", "Proceedings"}, - new Object[]{"BibTeX", "Manual"}, - new Object[]{"BibTeX", "MastersThesis"}, - new Object[]{"BibTeX", "PhdThesis"}, - new Object[]{"BibTeX", "TechReport"}, - new Object[]{"BibTeX", "Unpublished"}, - new Object[]{"BibTeX", "Misc"}, - new Object[]{"BibTeX", "Electronic"}, - new Object[]{"BibTeX", "IEEEtranBSTCTL"}, - new Object[]{"BibTeX", "Periodical"}, - new Object[]{"BibTeX", "Patent"}, - new Object[]{"BibTeX", "Standard"}, - new Object[]{"biblatex", "Article"}, - new Object[]{"biblatex", "Book"}, - new Object[]{"biblatex", "BookInBook"}, - new Object[]{"biblatex", "Booklet"}, - new Object[]{"biblatex", "Collection"}, - new Object[]{"biblatex", "Conference"}, - new Object[]{"biblatex", "Electronic"}, - new Object[]{"biblatex", "IEEEtranBSTCTL"}, - new Object[]{"biblatex", "InBook"}, - new Object[]{"biblatex", "InCollection"}, - new Object[]{"biblatex", "InProceedings"}, - new Object[]{"biblatex", "InReference"}, - new Object[]{"biblatex", "Manual"}, - new Object[]{"biblatex", "MastersThesis"}, - new Object[]{"biblatex", "Misc"}, - new Object[]{"biblatex", "MvBook"}, - new Object[]{"biblatex", "MvCollection"}, - new Object[]{"biblatex", "MvProceedings"}, - new Object[]{"biblatex", "MvReference"}, - new Object[]{"biblatex", "Online"}, - new Object[]{"biblatex", "Patent"}, - new Object[]{"biblatex", "Periodical"}, - new Object[]{"biblatex", "PhdThesis"}, - new Object[]{"biblatex", "Proceedings"}, - new Object[]{"biblatex", "Reference"}, - new Object[]{"biblatex", "Report"}, - new Object[]{"biblatex", "Set"}, - new Object[]{"biblatex", "SuppBook"}, - new Object[]{"biblatex", "SuppCollection"}, - new Object[]{"biblatex", "SuppPeriodical"}, - new Object[]{"biblatex", "TechReport"}, - new Object[]{"biblatex", "Thesis"}, - new Object[]{"biblatex", "Unpublished"},*/ - new Object[]{"biblatex", "WWW"} - ); - // @formatter:on - } -} diff --git a/src/test/java/org/jabref/gui/ParameterizedDialogTest.java b/src/test/java/org/jabref/gui/ParameterizedDialogTest.java deleted file mode 100644 index de3d6dcfc43..00000000000 --- a/src/test/java/org/jabref/gui/ParameterizedDialogTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.jabref.gui; - -import java.util.stream.Stream; - -import javax.swing.JButton; -import javax.swing.JDialog; - -import org.assertj.swing.core.GenericTypeMatcher; -import org.assertj.swing.dependency.jsr305.Nonnull; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import static org.assertj.swing.finder.WindowFinder.findDialog; - -@Tag("GUITest") -public class ParameterizedDialogTest extends AbstractUITest { - - @ParameterizedTest - @MethodSource("instancesToTest") - public void openAndExitDialog(boolean createDatabase, String[] menuPath, String dialogTitle, String buttonName, - boolean closeButton) { - if (createDatabase) { - newDatabase(); - } - mainFrame.menuItemWithPath(menuPath).click(); - GenericTypeMatcher matcher = new GenericTypeMatcher(JDialog.class) { - - @Override - protected boolean isMatching(JDialog dialog) { - return dialogTitle.equals(dialog.getTitle()); - } - }; - - if (closeButton) { - findDialog(matcher).withTimeout(10_000).using(robot()).close(); - } else { - findDialog(matcher).withTimeout(10_000).using(robot()) - .button(new GenericTypeMatcher(JButton.class) { - - @Override - protected boolean isMatching(@Nonnull JButton jButton) { - return buttonName.equals(jButton.getText()); - } - }).click(); - } - if (createDatabase) { - closeDatabase(); - } - exitJabRef(); - } - - public static Stream instancesToTest() { - // Opening and closing (in different ways) the dialogs accessible from the menus without doing anything else - // Structure: - // {create new database, {"Menu", "Submenu", "Sub-sub-menu"}, "Dialog title", "Button name", use close button} - // @formatter:off - return Stream.of( - new Object[]{false, new String[]{"File", "Open library"}, "Open", "Cancel", false}, - new Object[]{false, new String[]{"File", "Open library"}, "Open", "Close button", true}, - new Object[]{true, new String[]{"File", "Append library"}, "Append library", "Cancel", false}, - new Object[]{true, new String[]{"File", "Append library"}, "Append library", "Close button", true}, - new Object[]{true, new String[]{"File", "Save library"}, "Save", "Cancel", false}, - new Object[]{true, new String[]{"File", "Save library"}, "Save", "Close button", true}, - new Object[]{true, new String[]{"File", "Save library as..."}, "Save", "Cancel", false}, - new Object[]{true, new String[]{"File", "Save library as..."}, "Save", "Close button", true}, - new Object[]{true, new String[]{"File", "Save all"}, "Save", "Cancel", false}, - new Object[]{true, new String[]{"File", "Save all"}, "Save", "Close button", true}, - new Object[]{false, new String[]{"File", "Import into new library"}, "Open", "Cancel", false}, - new Object[]{false, new String[]{"File", "Import into new library"}, "Open", "Close button", true}, - new Object[]{true, new String[]{"File", "Import into current library"}, "Open", "Cancel", false}, - new Object[]{true, new String[]{"File", "Import into current library"}, "Open", "Close button", true}, - new Object[]{true, new String[]{"File", "Export"}, "Save", "Cancel", false}, - new Object[]{true, new String[]{"File", "Export"}, "Save", "Close button", true}, - new Object[]{true, new String[]{"File", "Open shared database"}, "Open shared database", "Cancel", false}, - new Object[]{true, new String[]{"File", "Library properties"}, "Library properties", "Cancel", false}, - new Object[]{true, new String[]{"File", "Library properties"}, "Library properties", "OK", false}, - new Object[]{true, new String[]{"File", "Library properties"}, "Library properties", "Close button", true}, - new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "Cancel", false}, - //new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "OK", false}, - new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "Close button", true}, - new Object[]{true, new String[]{"Search", "Replace string..."}, "Replace string", "Cancel", false}, - new Object[]{true, new String[]{"Search", "Replace string..."}, "Replace string", "Close button", true}, - new Object[]{true, new String[]{"Groups", "Add to group..."}, "Add to group", "Cancel", false}, - new Object[]{true, new String[]{"Groups", "Add to group..."}, "Add to group", "Close button", true}, - new Object[]{true, new String[]{"Groups", "Remove from group..."}, "Remove from group", "Cancel", false}, - new Object[]{true, new String[]{"Groups", "Remove from group..."}, "Remove from group", "Close button", true}, - new Object[]{true, new String[]{"Groups", "Move to group..."}, "Move to group", "Cancel", false}, - new Object[]{true, new String[]{"Groups", "Move to group..."}, "Move to group", "Close button", true}, - new Object[]{true, new String[]{"BibTeX", "New entry..."}, "Select entry type", "Cancel", false}, - new Object[]{true, new String[]{"BibTeX", "New entry..."}, "Select entry type", "Close button", true}, - new Object[]{true, new String[]{"BibTeX", "Edit preamble"}, "Edit preamble", "Close button", true}, - new Object[]{true, new String[]{"BibTeX", "Edit strings"}, "Strings for library: untitled", "Close button", true}, - new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "Cancel", false}, - new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "OK", false}, - new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "Close button", true}, - new Object[]{true, new String[]{"Quality", "Synchronize file links..."}, "Synchronize file links", "Cancel", false}, - new Object[]{true, new String[]{"Quality", "Synchronize file links..."}, "Synchronize file links", "Close button", true}, - new Object[]{true, new String[]{"Quality", "Find unlinked files..."}, "Find unlinked files", "Close", false}, - new Object[]{true, new String[]{"Quality", "Find unlinked files..."}, "Find unlinked files", "Close button", true}, - new Object[]{true, new String[]{"Tools", "New sublibrary based on AUX file..."}, "AUX file import", "Cancel", false}, - new Object[]{true, new String[]{"Tools", "New sublibrary based on AUX file..."}, "AUX file import", "Close button", true}, - new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "Cancel", false}, - new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "OK", false}, - new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "Close button", true}, - new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "Cancel", false}, - new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "OK", false}, - new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "Close button", true}, - new Object[]{false, new String[]{"Options", "Manage custom exports"}, "Manage custom exports", "Close", false}, - new Object[]{false, new String[]{"Options", "Manage custom exports"}, "Manage custom exports", "Close button", true}, - new Object[]{false, new String[]{"Options", "Manage custom imports"}, "Manage custom imports", "Close", false}, - new Object[]{false, new String[]{"Options", "Manage custom imports"}, "Manage custom imports", "Close button", true}, - new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "Cancel", false}, - new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "OK", false}, - new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "Close button", true}, - new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "Cancel", false}, - new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "OK", false}, - new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "Close button", true}, - new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "Cancel", false}, - // new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "OK", false}, - new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "Close button", true}, - new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "Cancel", false}, - new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "OK", false}, - new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "Close button", true}, - new Object[]{false, new String[]{"Options", "Customize key bindings"}, "Key bindings", "Cancel", false}, - new Object[]{false, new String[]{"Options", "Customize key bindings"}, "Key bindings", "Close button", true}, - new Object[]{false, new String[]{"Help", "Show error console"}, "Program output", "OK", false}, - new Object[]{false, new String[]{"Help", "Show error console"}, "Program output", "Close button", true}, - new Object[]{false, new String[]{"Help", "About JabRef"}, "About JabRef", "Close button", true} - ); - // @formatter:on - } -} diff --git a/src/test/java/org/jabref/gui/ParameterizedMenuNewEntryTest.java b/src/test/java/org/jabref/gui/ParameterizedMenuNewEntryTest.java deleted file mode 100644 index 67efff9e04b..00000000000 --- a/src/test/java/org/jabref/gui/ParameterizedMenuNewEntryTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.jabref.gui; - -import java.util.stream.Stream; - -import org.jabref.model.strings.StringUtil; - -import org.assertj.swing.fixture.JTableFixture; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -@Tag("GUITest") -public class ParameterizedMenuNewEntryTest extends AbstractUITest { - - // Not working on Travis - @ParameterizedTest - @MethodSource("instancesToTest") - public void addEntryOfGivenType(String databaseMode, String entryType) { - mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click(); - JTableFixture entryTable = mainFrame.table(); - - entryTable.requireRowCount(0); - mainFrame.menuItemWithPath("BibTeX", "New entry by type...", StringUtil.capitalizeFirst(entryType)).click(); - entryTable.requireRowCount(1); - } - - public static Stream instancesToTest() { - // Create entry from menu - // Structure: - // {"BibTeX"/"biblatex", "type"} - // @formatter:off - return Stream.of( - new Object[]{"BibTeX", "article"}, - new Object[]{"BibTeX", "inbook"}, - new Object[]{"BibTeX", "book"}, - new Object[]{"BibTeX", "booklet"}, - new Object[]{"BibTeX", "incollection"}, - new Object[]{"BibTeX", "conference"}, - new Object[]{"BibTeX", "inproceedings"}, - new Object[]{"BibTeX", "proceedings"}, - new Object[]{"BibTeX", "manual"}, - new Object[]{"BibTeX", "mastersthesis"}, - new Object[]{"BibTeX", "phdthesis"}, - new Object[]{"BibTeX", "techreport"}, - new Object[]{"BibTeX", "unpublished"}, - new Object[]{"BibTeX", "misc"}, - new Object[]{"biblatex", "article"}, - new Object[]{"biblatex", "inbook"}, - new Object[]{"biblatex", "book"}, - new Object[]{"biblatex", "booklet"}, - new Object[]{"biblatex", "incollection"}, - new Object[]{"biblatex", "conference"}, - new Object[]{"biblatex", "inproceedings"}, - new Object[]{"biblatex", "proceedings"}, - new Object[]{"biblatex", "manual"}, - new Object[]{"biblatex", "mastersthesis"}, - new Object[]{"biblatex", "phdthesis"}, - new Object[]{"biblatex", "techreport"}, - new Object[]{"biblatex", "unpublished"}, - new Object[]{"biblatex", "misc"} - ); - // @formatter:on - } -} diff --git a/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java b/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java index df3012e67ad..c3f50e3c853 100644 --- a/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java +++ b/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java @@ -6,13 +6,14 @@ import javafx.scene.control.TabPane; import javafx.stage.Stage; -import org.jabref.gui.FXDialogService; +import org.jabref.gui.DialogService; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.util.DummyFileUpdateMonitor; +import org.jabref.testutils.category.GUITest; import org.fxmisc.richtext.CodeArea; import org.junit.jupiter.api.Test; @@ -23,6 +24,7 @@ import static org.mockito.Mockito.mock; +@GUITest @ExtendWith(ApplicationExtension.class) public class SourceTabTest { @@ -36,7 +38,7 @@ public class SourceTabTest { public void onStart(Stage stage) { area = new CodeArea(); area.appendText("some example\n text to go here\n across a couple of \n lines...."); - sourceTab = new SourceTab(new BibDatabaseContext(), new CountingUndoManager(), new LatexFieldFormatterPreferences(), mock(ImportFormatPreferences.class), new DummyFileUpdateMonitor(), new FXDialogService()); + sourceTab = new SourceTab(new BibDatabaseContext(), new CountingUndoManager(), new LatexFieldFormatterPreferences(), mock(ImportFormatPreferences.class), new DummyFileUpdateMonitor(), mock(DialogService.class)); pane = new TabPane( new Tab("main area", area), new Tab("other tab", new Label("some text")), diff --git a/src/test/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtilTest.java b/src/test/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtilTest.java index ae1b46fe557..54be381f4b5 100644 --- a/src/test/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtilTest.java +++ b/src/test/java/org/jabref/gui/externalfiles/AutoSetFileLinksUtilTest.java @@ -16,15 +16,13 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) public class AutoSetFileLinksUtilTest { private final FilePreferences fileDirPrefs = mock(FilePreferences.class); @@ -34,7 +32,7 @@ public class AutoSetFileLinksUtilTest { private final BibEntry entry = new BibEntry(BibtexEntryTypes.ARTICLE); @BeforeEach - public void setUp(@TempDirectory.TempDir Path folder) throws Exception { + public void setUp(@TempDir Path folder) throws Exception { Path path = folder.resolve("CiteKey.pdf"); Files.createFile(path); entry.setCiteKey("CiteKey"); diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java index a2fcce655cf..7a7893c6d79 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java @@ -17,8 +17,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -31,7 +30,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) class LinkedFileViewModelTest { private Path tempFile; @@ -43,7 +41,7 @@ class LinkedFileViewModelTest { private DialogService dialogService; @BeforeEach - void setUp(@TempDirectory.TempDir Path tempFolder) throws Exception { + void setUp(@TempDir Path tempFolder) throws Exception { entry = new BibEntry(); databaseContext = new BibDatabaseContext(); taskExecutor = mock(TaskExecutor.class); diff --git a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java b/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java deleted file mode 100644 index 49a5a5c8b91..00000000000 --- a/src/test/java/org/jabref/gui/importer/EntryFromFileCreatorManagerTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.jabref.gui.importer; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; - -import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.logic.importer.ImportDataTest; -import org.jabref.logic.importer.ImportFormatPreferences; -import org.jabref.logic.importer.ParserResult; -import org.jabref.logic.importer.fileformat.BibtexImporter; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.FileFieldParser; -import org.jabref.model.entry.LinkedFile; -import org.jabref.model.util.DummyFileUpdateMonitor; -import org.jabref.testutils.category.GUITest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Answers; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@GUITest -class EntryFromFileCreatorManagerTest { - - private final ImportFormatPreferences prefs = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); - private EntryFromFileCreatorManager manager; - - @BeforeEach - void setUp() { - ExternalFileTypes externalFileTypes = mock(ExternalFileTypes.class, Answers.RETURNS_DEEP_STUBS); - when(externalFileTypes.getExternalFileTypeByExt("pdf")).thenReturn(Optional.empty()); - manager = new EntryFromFileCreatorManager(externalFileTypes); - } - - @Test - void getEntryCreatorForNotExistingPDFReturnsEmptyOptional() { - assertEquals(Optional.empty(), manager.getEntryCreator(ImportDataTest.NOT_EXISTING_PDF)); - } - - @Test - void getEntryCreatorForExistingPDFReturnsCreatorAcceptingThatFile() { - Optional creator = manager.getEntryCreator(ImportDataTest.FILE_IN_DATABASE); - assertNotEquals(Optional.empty(), creator); - assertTrue(creator.get().accept(ImportDataTest.FILE_IN_DATABASE.toFile())); - } - - @Test - void testAddEntriesFromFiles() throws IOException { - ParserResult result = new BibtexImporter(prefs, new DummyFileUpdateMonitor()) - .importDatabase(ImportDataTest.UNLINKED_FILES_TEST_BIB, StandardCharsets.UTF_8); - BibDatabase database = result.getDatabase(); - - List files = new ArrayList<>(); - files.add(ImportDataTest.FILE_NOT_IN_DATABASE); - files.add(ImportDataTest.NOT_EXISTING_PDF); - - List errors = manager.addEntrysFromFiles(files, database, null, true); - - // One file doesn't exist, so adding it as an entry should lead to an error message. - assertEquals(1, errors.size()); - - Stream linkedFileStream = database.getEntries().stream() - .flatMap(entry -> FileFieldParser.parse(entry.getField("file").get()).stream()); - - boolean file1Found = linkedFileStream - .anyMatch(file -> file.getLink().equalsIgnoreCase(ImportDataTest.FILE_NOT_IN_DATABASE.toString())); - - boolean file2Found = linkedFileStream - .anyMatch(file -> file.getLink().equalsIgnoreCase(ImportDataTest.NOT_EXISTING_PDF.toString())); - - assertTrue(file1Found); - assertFalse(file2Found); - } -} diff --git a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java b/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java deleted file mode 100644 index 0a49334f501..00000000000 --- a/src/test/java/org/jabref/gui/importer/EntryFromPDFCreatorTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.jabref.gui.importer; - -import java.io.File; -import java.util.Optional; - -import org.jabref.JabRefGUI; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.logic.importer.ImportDataTest; -import org.jabref.model.entry.BibEntry; -import org.jabref.testutils.category.GUITest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.mockito.Answers; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; - -@GUITest -public class EntryFromPDFCreatorTest { - - private EntryFromPDFCreator entryCreator; - - @BeforeEach - public void setUp() { - // Needed to initialize ExternalFileTypes - entryCreator = new EntryFromPDFCreator(mock(ExternalFileTypes.class, Answers.RETURNS_DEEP_STUBS)); - - // Needed for PdfImporter - still not enough - JabRefGUI.setMainFrame(mock(JabRefFrame.class)); - } - - @Test - public void testPDFFileFilter() { - assertTrue(entryCreator.accept(new File("aPDF.pdf"))); - assertTrue(entryCreator.accept(new File("aPDF.PDF"))); - assertFalse(entryCreator.accept(new File("foo.jpg"))); - } - - @Test - public void testCreationOfEntryNoPDF() { - Optional entry = entryCreator.createEntry(ImportDataTest.NOT_EXISTING_PDF.toFile(), false); - assertFalse(entry.isPresent()); - } - - @Test - @Disabled //Can't mock basepanel and maintable - public void testCreationOfEntryNotInDatabase() { - Optional entry = entryCreator.createEntry(ImportDataTest.FILE_NOT_IN_DATABASE.toFile(), false); - assertTrue(entry.isPresent()); - assertTrue(entry.get().getField("file").get().endsWith(":PDF")); - assertEquals(Optional.of(ImportDataTest.FILE_NOT_IN_DATABASE.getFileName().toString()), - entry.get().getField("title")); - } -} diff --git a/src/test/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModelTest.java b/src/test/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModelTest.java index 77e7d20cc36..96f00ed4065 100644 --- a/src/test/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModelTest.java +++ b/src/test/java/org/jabref/gui/journals/ManageJournalAbbreviationsViewModelTest.java @@ -23,8 +23,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.jabref.logic.util.OS.NEWLINE; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -37,7 +36,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) class ManageJournalAbbreviationsViewModelTest { private ManageJournalAbbreviationsViewModel viewModel; @@ -50,7 +48,7 @@ class ManageJournalAbbreviationsViewModelTest { private DialogService dialogService; @BeforeEach - void setUpViewModel(@TempDirectory.TempDir Path tempFolder) throws Exception { + void setUpViewModel(@TempDir Path tempFolder) throws Exception { abbreviationPreferences = mock(JournalAbbreviationPreferences.class); PreferencesService preferences = mock(PreferencesService.class); when(preferences.getJournalAbbreviationPreferences()).thenReturn(abbreviationPreferences); diff --git a/src/test/java/org/jabref/gui/mergeentries/DiffHighlightingTest.java b/src/test/java/org/jabref/gui/mergeentries/DiffHighlightingTest.java index 70d0b601cd6..9ed45408946 100644 --- a/src/test/java/org/jabref/gui/mergeentries/DiffHighlightingTest.java +++ b/src/test/java/org/jabref/gui/mergeentries/DiffHighlightingTest.java @@ -7,11 +7,14 @@ import javafx.scene.text.Text; +import org.jabref.testutils.category.GUITest; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.testfx.framework.junit5.ApplicationExtension; +@GUITest @ExtendWith(ApplicationExtension.class) class DiffHighlightingTest { diff --git a/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java b/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java index 278556f0db4..cfc515f5949 100644 --- a/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java +++ b/src/test/java/org/jabref/gui/search/ContainsAndRegexBasedSearchRuleDescriberTest.java @@ -9,12 +9,14 @@ import org.jabref.gui.search.rules.describer.ContainsAndRegexBasedSearchRuleDescriber; import org.jabref.gui.util.TooltipTextUtil; +import org.jabref.testutils.category.GUITest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.testfx.framework.junit5.ApplicationExtension; import org.testfx.framework.junit5.Start; +@GUITest @ExtendWith(ApplicationExtension.class) class ContainsAndRegexBasedSearchRuleDescriberTest { diff --git a/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java b/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java index 7855be39bae..36ae0dbea71 100644 --- a/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java +++ b/src/test/java/org/jabref/gui/search/GrammarBasedSearchRuleDescriberTest.java @@ -10,6 +10,7 @@ import org.jabref.gui.search.rules.describer.GrammarBasedSearchRuleDescriber; import org.jabref.gui.util.TooltipTextUtil; import org.jabref.model.search.rules.GrammarBasedSearchRule; +import org.jabref.testutils.category.GUITest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; +@GUITest @ExtendWith(ApplicationExtension.class) class GrammarBasedSearchRuleDescriberTest { diff --git a/src/test/java/org/jabref/gui/search/SearchResultsTest.java b/src/test/java/org/jabref/gui/search/SearchResultsTest.java deleted file mode 100644 index 1e2badcc2ad..00000000000 --- a/src/test/java/org/jabref/gui/search/SearchResultsTest.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.jabref.gui.search; - -import java.util.concurrent.TimeUnit; - -import javax.swing.JFrame; - -import org.jabref.testutils.TestUtils; - -import org.assertj.swing.core.ComponentFinder; -import org.assertj.swing.edt.FailOnThreadViolationRepaintManager; -import org.assertj.swing.finder.WindowFinder; -import org.assertj.swing.fixture.FrameFixture; -import org.assertj.swing.fixture.JTextComponentFixture; -import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; - -@Tag("GUITest") -public class SearchResultsTest extends AssertJSwingJUnitTestCase { - - private FrameFixture frameFixture; - - @BeforeAll - public static void before() { - FailOnThreadViolationRepaintManager.uninstall(); - } - - @Override - protected void onSetUp() { - TestUtils.initJabRef(); - frameFixture = WindowFinder.findFrame(JFrame.class).withTimeout(15, TimeUnit.SECONDS).using(robot()); - } - - @Override - protected void onTearDown() { - frameFixture.close(); - frameFixture = null; - - TestUtils.closeJabRef(); - } - - @Test - public void testSearchFieldQuery() { - frameFixture.menuItemWithPath("Search", "Search").click(); - JTextComponentFixture searchField = frameFixture.textBox(); - ComponentFinder finder = robot().finder(); - /* - BasePanel panel = finder.findByType(BasePanel.class); - Collection entries = panel.getDatabase().getEntries(); - - searchField.deleteText().enterText(""); - Assert.assertEquals(19, entries.size()); - - searchField.deleteText().enterText("entrytype=article"); - Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit())); - Assert.assertEquals(5, entries.stream().filter(entry -> entry.isSearchHit()).count()); - - searchField.deleteText().enterText("entrytype=proceedings"); - Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit())); - Assert.assertEquals(13, entries.stream().filter(entry -> entry.isSearchHit()).count()); - - searchField.deleteText().enterText("entrytype=book"); - Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit())); - Assert.assertEquals(1, entries.stream().filter(entry -> entry.isSearchHit()).count()); - */ - } - - @Test - public void testSeachWithoutResults() { - /* - frameFixture.menuItemWithPath("Search", "Search").click(); - JTextComponentFixture searchField = frameFixture.textBox(); - ComponentFinder finder = robot().finder(); - BasePanel panel = finder.findByType(BasePanel.class); - Collection entries = panel.getDatabase().getEntries(); - - searchField.deleteText().enterText("asdf"); - Assert.assertTrue(entries.stream().noneMatch(entry -> entry.isSearchHit())); - */ - } - - @Test - public void testSearchInvalidQuery() { - /* - frameFixture.menuItemWithPath("Search", "Search").click(); - JTextComponentFixture searchField = frameFixture.textBox(); - ComponentFinder finder = robot().finder(); - BasePanel panel = finder.findByType(BasePanel.class); - Collection entries = panel.getDatabase().getEntries(); - - searchField.deleteText().enterText("asdf["); - Assert.assertTrue(entries.stream().noneMatch(entry -> entry.isSearchHit())); - */ - } -} diff --git a/src/test/java/org/jabref/gui/util/FileDialogConfigurationTest.java b/src/test/java/org/jabref/gui/util/FileDialogConfigurationTest.java index 2a19e5593a6..5f608f0ef4a 100644 --- a/src/test/java/org/jabref/gui/util/FileDialogConfigurationTest.java +++ b/src/test/java/org/jabref/gui/util/FileDialogConfigurationTest.java @@ -12,16 +12,14 @@ import org.jabref.logic.util.StandardFileType; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; -@ExtendWith(TempDirectory.class) class FileDialogConfigurationTest { @Test - void testWithValidDirectoryString(@TempDirectory.TempDir Path folder) { + void testWithValidDirectoryString(@TempDir Path folder) { String tempFolder = folder.toAbsolutePath().toString(); FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() @@ -31,7 +29,7 @@ void testWithValidDirectoryString(@TempDirectory.TempDir Path folder) { } @Test - void testWithValidDirectoryPath(@TempDirectory.TempDir Path tempFolder) { + void testWithValidDirectoryPath(@TempDir Path tempFolder) { FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() .withInitialDirectory(tempFolder).build(); diff --git a/src/test/java/org/jabref/logic/TypedBibEntryTest.java b/src/test/java/org/jabref/logic/TypedBibEntryTest.java index 9415bdcd28c..a80f7dde9d7 100644 --- a/src/test/java/org/jabref/logic/TypedBibEntryTest.java +++ b/src/test/java/org/jabref/logic/TypedBibEntryTest.java @@ -38,7 +38,7 @@ public void hasAllRequiredFields() { @Test public void hasAllRequiredFieldsForUnknownTypeReturnsTrue() { - BibEntry e = new BibEntry(new CustomEntryType("articlllleeeee","required","optional")); + BibEntry e = new BibEntry(new CustomEntryType("articlllleeeee", "required", "optional")); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); assertTrue(typedEntry.hasAllRequiredFields()); @@ -54,7 +54,7 @@ public void getTypeForDisplayReturnsTypeName() { @Test public void getTypeForDisplayForUnknownTypeCapitalizeFirstLetter() { - BibEntry e = new BibEntry(new CustomEntryType("articlllleeeee","required","optional")); + BibEntry e = new BibEntry(new CustomEntryType("articlllleeeee", "required", "optional")); TypedBibEntry typedEntry = new TypedBibEntry(e, BibDatabaseMode.BIBTEX); assertEquals("Articlllleeeee", typedEntry.getTypeForDisplay()); diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java index 4ed5b5bb728..ad6e2d86e1c 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGeneratorTest.java @@ -119,73 +119,73 @@ public void testMakeLabelAndCheckLegalKeys() throws ParseException { Optional entry0 = BibtexParser.singleFromString( "@ARTICLE{kohn, author={Andreas Köning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Koen", + assertEquals("Koe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Áöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Aoen", + assertEquals("Aoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Éöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Eoen", + assertEquals("Eoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Íöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Ioen", + assertEquals("Ioe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ĺöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Loen", + assertEquals("Loe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ńöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Noen", + assertEquals("Noe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Óöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Ooen", + assertEquals("Ooe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ŕöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Roen", + assertEquals("Roe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Śöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Soen", + assertEquals("Soe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Úöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Uoen", + assertEquals("Uoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ýöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Yoen", + assertEquals("Yoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Źöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Zoen", + assertEquals("Zoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); } @@ -197,31 +197,43 @@ public void testMakeLabelAndCheckLegalKeys() throws ParseException { public void testMakeLabelAndCheckLegalKeysAccentGrave() throws ParseException { Optional entry0 = BibtexParser.singleFromString( "@ARTICLE{kohn, author={Andreas Àöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Aoen", + assertEquals("Aoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Èöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Eoen", + assertEquals("Eoe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ìöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Ioen", + assertEquals("Ioe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Òöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Ooen", + assertEquals("Ooe", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ùöning}, year={2000}}", importFormatPreferences, fileMonitor); - assertEquals("Uoen", + assertEquals("Uoe", + BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + new BibDatabase()), true)); + + entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Oraib Al-Ketan}, year={2000}}", + importFormatPreferences, fileMonitor); + assertEquals("AlK", + BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", + new BibDatabase()), true)); + + entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andrés D'Alessandro}, year={2000}}", + importFormatPreferences, fileMonitor); + assertEquals("DAl", BibtexKeyGenerator.cleanKey(BibtexKeyGenerator.generateKey(entry0.get(), "auth3", new BibDatabase()), true)); } @@ -1007,4 +1019,66 @@ public void generateKeyWithTwoModifiers() throws Exception { entry.setField("title", "The Interesting Title"); assertEquals("theinterestingtitle", BibtexKeyGenerator.generateKey(entry, "title:lower:(_)")); } + + @Test + public void generateKeyWithTitleCapitalizeModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("title", "the InTeresting title longer than THREE words"); + assertEquals("TheInterestingTitleLongerThanThreeWords", BibtexKeyGenerator.generateKey(entry, "title:capitalize")); + } + + @Test + public void generateKeyWithShortTitleCapitalizeModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("title", "the InTeresting title longer than THREE words"); + assertEquals("InterestingTitleLonger", BibtexKeyGenerator.generateKey(entry, "shorttitle:capitalize")); + } + + @Test + public void generateKeyWithTitleTitleCaseModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("title", "A title WITH some of The key words"); + assertEquals("ATitlewithSomeoftheKeyWords", BibtexKeyGenerator.generateKey(entry, "title:titlecase")); + } + + @Test + public void generateKeyWithShortTitleTitleCaseModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("title", "the InTeresting title longer than THREE words"); + assertEquals("InterestingTitleLonger", BibtexKeyGenerator.generateKey(entry, "shorttitle:titlecase")); + } + + @Test + public void generateKeyWithTitleSentenceCaseModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("title", "A title WITH some of The key words"); + assertEquals("Atitlewithsomeofthekeywords", BibtexKeyGenerator.generateKey(entry, "title:sentencecase")); + } + + @Test + public void generateKeyWithAuthUpperYearShortTitleCapitalizeModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("author", AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_1); + entry.setField("year", "2019"); + entry.setField("title", "the InTeresting title longer than THREE words"); + assertEquals("NEWTON2019InterestingTitleLonger", BibtexKeyGenerator.generateKey(entry, "[auth:upper][year][shorttitle:capitalize]")); + } + + @Test + public void generateKeyWithYearAuthUpperTitleSentenceCaseModifier() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("author", AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_3); + entry.setField("year", "2019"); + entry.setField("title", "the InTeresting title longer than THREE words"); + assertEquals("NewtonMaxwellEtAl_2019_TheInterestingTitleLongerThanThreeWords", BibtexKeyGenerator.generateKey(entry, "[authors2]_[year]_[title:capitalize]")); + } + + @Test + public void generateKeyWithMinusInCitationStyleOutsideAField() throws Exception { + BibEntry entry = new BibEntry(); + entry.setField("author", AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_1); + entry.setField("year", "2019"); + + assertEquals("Newton-2019", BibtexKeyGenerator.generateKey(entry, "[auth]-[year]")); + } } diff --git a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java index a28d412bc35..88345234b72 100644 --- a/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java +++ b/src/test/java/org/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java @@ -397,7 +397,7 @@ void generateKeyTitleRegexe() { bibtexKeyPattern.setDefaultValue("[title:regex(\" \",\"-\")]"); entry.setField("title", "Please replace the spaces"); new BibtexKeyGenerator(bibtexKeyPattern, database, preferences).generateAndSetKey(entry); - assertEquals(Optional.of("Please-Replace-the-Spaces"), entry.getCiteKeyOptional()); + assertEquals(Optional.of("PleaseReplacetheSpaces"), entry.getCiteKeyOptional()); } @Test diff --git a/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java b/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java index 567dffd1f6a..46431376144 100644 --- a/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java +++ b/src/test/java/org/jabref/logic/cleanup/CleanupWorkerTest.java @@ -34,8 +34,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -44,14 +43,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) class CleanupWorkerTest { private final CleanupPreset emptyPreset = new CleanupPreset(EnumSet.noneOf(CleanupPreset.CleanupStep.class)); private CleanupWorker worker; @BeforeEach - void setUp(@TempDirectory.TempDir Path bibFolder) throws IOException { + void setUp(@TempDir Path bibFolder) throws IOException { Path path = bibFolder.resolve("ARandomlyNamedFolder"); Files.createDirectory(path); @@ -82,7 +80,7 @@ void cleanupNullEntryThrowsException() { } @Test - void cleanupDoesNothingByDefault(@TempDirectory.TempDir Path bibFolder) throws IOException { + void cleanupDoesNothingByDefault(@TempDir Path bibFolder) throws IOException { BibEntry entry = new BibEntry(); entry.setCiteKey("Toot"); entry.setField("pdf", "aPdfFile"); @@ -220,7 +218,7 @@ void cleanupFixFileLinksMovesSingleDescriptionToLink() { } @Test - void cleanupMoveFilesMovesFileFromSubfolder(@TempDirectory.TempDir Path bibFolder) throws IOException { + void cleanupMoveFilesMovesFileFromSubfolder(@TempDir Path bibFolder) throws IOException { CleanupPreset preset = new CleanupPreset(CleanupPreset.CleanupStep.MOVE_PDF); Path path = bibFolder.resolve("AnotherRandomlyNamedFolder"); @@ -238,7 +236,7 @@ void cleanupMoveFilesMovesFileFromSubfolder(@TempDirectory.TempDir Path bibFolde } @Test - void cleanupRelativePathsConvertAbsoluteToRelativePath(@TempDirectory.TempDir Path bibFolder) throws IOException { + void cleanupRelativePathsConvertAbsoluteToRelativePath(@TempDir Path bibFolder) throws IOException { CleanupPreset preset = new CleanupPreset(CleanupPreset.CleanupStep.MAKE_PATHS_RELATIVE); Path path = bibFolder.resolve("AnotherRandomlyNamedFile"); @@ -254,7 +252,7 @@ void cleanupRelativePathsConvertAbsoluteToRelativePath(@TempDirectory.TempDir Pa } @Test - void cleanupRenamePdfRenamesRelativeFile(@TempDirectory.TempDir Path bibFolder) throws IOException { + void cleanupRenamePdfRenamesRelativeFile(@TempDir Path bibFolder) throws IOException { CleanupPreset preset = new CleanupPreset(CleanupPreset.CleanupStep.RENAME_PDF); Path path = bibFolder.resolve("AnotherRandomlyNamedFile.tmp"); diff --git a/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java index 9e9d21bfbd0..bfb0501b11a 100644 --- a/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/MoveFilesCleanupTest.java @@ -17,8 +17,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -26,7 +25,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) class MoveFilesCleanupTest { private Path defaultFileFolder; @@ -36,7 +34,7 @@ class MoveFilesCleanupTest { private FilePreferences filePreferences; @BeforeEach - void setUp(@TempDirectory.TempDir Path bibFolder) throws IOException { + void setUp(@TempDir Path bibFolder) throws IOException { // The folder where the files should be moved to defaultFileFolder = bibFolder.resolve("pdf"); Files.createDirectory(defaultFileFolder); diff --git a/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java b/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java index eb027f824d0..53449106ff4 100644 --- a/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java +++ b/src/test/java/org/jabref/logic/cleanup/RenamePdfCleanupTest.java @@ -17,14 +17,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) class RenamePdfCleanupTest { private BibEntry entry; @@ -33,7 +31,7 @@ class RenamePdfCleanupTest { private RenamePdfCleanup cleanup; @BeforeEach - void setUp(@TempDirectory.TempDir Path testFolder) { + void setUp(@TempDir Path testFolder) { Path path = testFolder.resolve("test.bib"); MetaData metaData = new MetaData(); BibDatabaseContext context = new BibDatabaseContext(new BibDatabase(), metaData, new Defaults()); @@ -51,7 +49,7 @@ void setUp(@TempDirectory.TempDir Path testFolder) { * Test for #466 */ @Test - void cleanupRenamePdfRenamesFileEvenIfOnlyDifferenceIsCase(@TempDirectory.TempDir Path testFolder) throws IOException { + void cleanupRenamePdfRenamesFileEvenIfOnlyDifferenceIsCase(@TempDir Path testFolder) throws IOException { Path path = testFolder.resolve("toot.tmp"); Files.createFile(path); @@ -66,7 +64,7 @@ void cleanupRenamePdfRenamesFileEvenIfOnlyDifferenceIsCase(@TempDirectory.TempDi } @Test - void cleanupRenamePdfRenamesWithMultipleFiles(@TempDirectory.TempDir Path testFolder) throws IOException { + void cleanupRenamePdfRenamesWithMultipleFiles(@TempDir Path testFolder) throws IOException { Path path = testFolder.resolve("Toot.tmp"); Files.createFile(path); @@ -84,7 +82,7 @@ void cleanupRenamePdfRenamesWithMultipleFiles(@TempDirectory.TempDir Path testFo } @Test - void cleanupRenamePdfRenamesFileStartingWithBibtexKey(@TempDirectory.TempDir Path testFolder) throws IOException { + void cleanupRenamePdfRenamesFileStartingWithBibtexKey(@TempDir Path testFolder) throws IOException { Path path = testFolder.resolve("Toot.tmp"); Files.createFile(path); @@ -100,7 +98,7 @@ void cleanupRenamePdfRenamesFileStartingWithBibtexKey(@TempDirectory.TempDir Pat } @Test - void cleanupRenamePdfRenamesFileInSameFolder(@TempDirectory.TempDir Path testFolder) throws IOException { + void cleanupRenamePdfRenamesFileInSameFolder(@TempDir Path testFolder) throws IOException { Path path = testFolder.resolve("Toot.pdf"); Files.createFile(path); LinkedFile fileField = new LinkedFile("", "Toot.pdf", "PDF"); diff --git a/src/test/java/org/jabref/logic/exporter/BibTeXMLExporterTestFiles.java b/src/test/java/org/jabref/logic/exporter/BibTeXMLExporterTestFiles.java index 85051a17351..a1513a6ee9f 100644 --- a/src/test/java/org/jabref/logic/exporter/BibTeXMLExporterTestFiles.java +++ b/src/test/java/org/jabref/logic/exporter/BibTeXMLExporterTestFiles.java @@ -18,10 +18,9 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.junitpioneer.jupiter.TempDirectory; import org.mockito.Answers; import org.xmlunit.builder.Input; import org.xmlunit.builder.Input.Builder; @@ -32,7 +31,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class BibTeXMLExporterTestFiles { private static Path resourceDir; @@ -52,7 +50,7 @@ public static Stream fileNames() throws IOException, URISyntaxException } @BeforeEach - public void setUp(@TempDirectory.TempDir Path testFolder) throws Exception { + public void setUp(@TempDir Path testFolder) throws Exception { databaseContext = new BibDatabaseContext(); charset = StandardCharsets.UTF_8; bibtexmlExportFormat = new BibTeXMLExporter(); diff --git a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java index e30ecf77ca8..c0d3994dbfc 100644 --- a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java +++ b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java @@ -435,7 +435,7 @@ void writeSaveActions() throws Exception { @Test void writeSaveOrderConfig() throws Exception { - SaveOrderConfig saveOrderConfig = new SaveOrderConfig(false, new SaveOrderConfig.SortCriterion("author", false), + SaveOrderConfig saveOrderConfig = new SaveOrderConfig(false, true, new SaveOrderConfig.SortCriterion("author", false), new SaveOrderConfig.SortCriterion("year", true), new SaveOrderConfig.SortCriterion("abstract", false)); metaData.setSaveOrderConfig(saveOrderConfig); @@ -485,17 +485,18 @@ void writeProtectedFlag() throws Exception { void writeFileDirectories() throws Exception { metaData.setDefaultFileDirectory("\\Literature\\"); metaData.setUserFileDirectory("defaultOwner-user", "D:\\Documents"); + metaData.setLaTexFileDirectory("defaultOwner-user", Paths.get("D:\\Latex")); databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList()); assertEquals(OS.NEWLINE + "@Comment{jabref-meta: fileDirectory:\\\\Literature\\\\;}" + OS.NEWLINE + OS.NEWLINE + "@Comment{jabref-meta: fileDirectory-defaultOwner-user:D:\\\\Documents;}" - + OS.NEWLINE, stringWriter.toString()); + + OS.NEWLINE + OS.NEWLINE + "@Comment{jabref-meta: fileDirectoryLatex-defaultOwner-user:D:\\\\Latex;}" + OS.NEWLINE, stringWriter.toString()); } @Test void writeEntriesSorted() throws Exception { - SaveOrderConfig saveOrderConfig = new SaveOrderConfig(false, + SaveOrderConfig saveOrderConfig = new SaveOrderConfig(false, true, new SaveOrderConfig.SortCriterion("author", false), new SaveOrderConfig.SortCriterion("year", true), new SaveOrderConfig.SortCriterion("abstract", false)); diff --git a/src/test/java/org/jabref/logic/exporter/CsvExportFormatTest.java b/src/test/java/org/jabref/logic/exporter/CsvExportFormatTest.java index a408b035221..1450f3d8295 100644 --- a/src/test/java/org/jabref/logic/exporter/CsvExportFormatTest.java +++ b/src/test/java/org/jabref/logic/exporter/CsvExportFormatTest.java @@ -17,14 +17,12 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class CsvExportFormatTest { public BibDatabaseContext databaseContext; @@ -51,7 +49,7 @@ public void tearDown() { } @Test - public void testPerformExportForSingleAuthor(@TempDirectory.TempDir Path testFolder) throws Exception { + public void testPerformExportForSingleAuthor(@TempDir Path testFolder) throws Exception { Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); BibEntry entry = new BibEntry(); @@ -68,7 +66,7 @@ public void testPerformExportForSingleAuthor(@TempDirectory.TempDir Path testFol } @Test - public void testPerformExportForMultipleAuthors(@TempDirectory.TempDir Path testFolder) throws Exception { + public void testPerformExportForMultipleAuthors(@TempDir Path testFolder) throws Exception { Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); BibEntry entry = new BibEntry(); @@ -85,7 +83,7 @@ public void testPerformExportForMultipleAuthors(@TempDirectory.TempDir Path test } @Test - public void testPerformExportForSingleEditor(@TempDirectory.TempDir Path testFolder) throws Exception { + public void testPerformExportForSingleEditor(@TempDir Path testFolder) throws Exception { Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); File tmpFile = path.toFile(); BibEntry entry = new BibEntry(); @@ -102,7 +100,7 @@ public void testPerformExportForSingleEditor(@TempDirectory.TempDir Path testFol } @Test - public void testPerformExportForMultipleEditors(@TempDirectory.TempDir Path testFolder) throws Exception { + public void testPerformExportForMultipleEditors(@TempDir Path testFolder) throws Exception { Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); File tmpFile = path.toFile(); BibEntry entry = new BibEntry(); diff --git a/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java b/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java index a97c72ef463..8b995bfa693 100644 --- a/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java +++ b/src/test/java/org/jabref/logic/exporter/DocBook5ExporterTest.java @@ -20,8 +20,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import org.xmlunit.builder.Input; import org.xmlunit.builder.Input.Builder; @@ -32,7 +31,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class DocBook5ExporterTest { public BibDatabaseContext databaseContext; @@ -43,7 +41,7 @@ public class DocBook5ExporterTest { private Exporter exportFormat; @BeforeEach - public void setUp() throws URISyntaxException { + void setUp() throws URISyntaxException { xmlFile = Paths.get(DocBook5ExporterTest.class.getResource("Docbook5ExportFormat.xml").toURI()); List customFormats = new ArrayList<>(); @@ -68,8 +66,7 @@ public void setUp() throws URISyntaxException { } @Test - public void testPerformExportForSingleEntry(@TempDirectory.TempDir Path testFolder) throws Exception { - + void testPerformExportForSingleEntry(@TempDir Path testFolder) throws Exception { Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); exportFormat.export(databaseContext, path, charset, entries); @@ -80,5 +77,4 @@ public void testPerformExportForSingleEntry(@TempDirectory.TempDir Path testFold assertThat(test, CompareMatcher.isSimilarTo(control) .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).throwComparisonFailure()); } - } diff --git a/src/test/java/org/jabref/logic/exporter/DocbookExporterTest.java b/src/test/java/org/jabref/logic/exporter/DocbookExporterTest.java new file mode 100644 index 00000000000..a10a91ec6ff --- /dev/null +++ b/src/test/java/org/jabref/logic/exporter/DocbookExporterTest.java @@ -0,0 +1,74 @@ +package org.jabref.logic.exporter; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.xmp.XmpPreferences; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.entry.BibEntry; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Answers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +public class DocbookExporterTest { + + public BibDatabaseContext databaseContext = new BibDatabaseContext();; + public Charset charset = StandardCharsets.UTF_8; + + private Exporter exportFormat; + + @BeforeEach + public void setUp() { + List customFormats = new ArrayList<>(); + LayoutFormatterPreferences layoutPreferences = mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS); + SavePreferences savePreferences = mock(SavePreferences.class); + XmpPreferences xmpPreferences = mock(XmpPreferences.class); + ExporterFactory exporterFactory = ExporterFactory.create(customFormats, layoutPreferences, savePreferences, xmpPreferences); + + exportFormat = exporterFactory.getExporterByName("docbook4").get(); + } + + @Test + public void testCorruptedTitleBraces(@TempDir Path testFolder) throws Exception { + Path tmpFile = testFolder.resolve("testBraces"); + + BibEntry entry = new BibEntry(); + entry.setField("title", "Peptidomics of the larval {\\protect{{D}rosophila melanogaster}} central nervous system."); + + List entries = Arrays.asList(entry); + + exportFormat.export(databaseContext, tmpFile, charset, entries); + + List lines = Files.readAllLines(tmpFile); + assertEquals(20, lines.size()); + assertEquals(" Peptidomics of the larval Drosophila melanogaster central nervous system.", lines.get(9)); + } + + @Test + public void testCorruptedTitleUnicode(@TempDir Path testFolder) throws Exception { + Path tmpFile = testFolder.resolve("testBraces"); + + BibEntry entry = new BibEntry(); + entry.setField("title", "Insect neuropeptide bursicon homodimers induce innate immune and stress genes during molting by activating the {NF}-$\\kappa$B transcription factor Relish."); + + List entries = Arrays.asList(entry); + + exportFormat.export(databaseContext, tmpFile, charset, entries); + + List lines = Files.readAllLines(tmpFile); + assertEquals(20, lines.size()); + assertEquals(" Insect neuropeptide bursicon homodimers induce innate immune and stress genes during molting by activating the NF-κB transcription factor Relish.", lines.get(9)); + } + +} diff --git a/src/test/java/org/jabref/logic/exporter/ExporterTest.java b/src/test/java/org/jabref/logic/exporter/ExporterTest.java index 67c7087f8da..ef33a47b167 100644 --- a/src/test/java/org/jabref/logic/exporter/ExporterTest.java +++ b/src/test/java/org/jabref/logic/exporter/ExporterTest.java @@ -16,16 +16,14 @@ import org.jabref.model.entry.BibEntry; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.junitpioneer.jupiter.TempDirectory; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class ExporterTest { public BibDatabaseContext databaseContext; @@ -56,7 +54,7 @@ private static Stream exportFormats() { @ParameterizedTest @MethodSource("exportFormats") - public void testExportingEmptyDatabaseYieldsEmptyFile(Exporter exportFormat, String name, @TempDirectory.TempDir Path testFolder) throws Exception { + public void testExportingEmptyDatabaseYieldsEmptyFile(Exporter exportFormat, String name, @TempDir Path testFolder) throws Exception { Path tmpFile = testFolder.resolve("ARandomlyNamedFile"); Files.createFile(tmpFile); exportFormat.export(databaseContext, tmpFile, charset, entries); @@ -65,7 +63,7 @@ public void testExportingEmptyDatabaseYieldsEmptyFile(Exporter exportFormat, Str @ParameterizedTest @MethodSource("exportFormats") - public void testExportingNullDatabaseThrowsNPE(Exporter exportFormat, String name, @TempDirectory.TempDir Path testFolder) { + public void testExportingNullDatabaseThrowsNPE(Exporter exportFormat, String name, @TempDir Path testFolder) { assertThrows(NullPointerException.class, () -> { Path tmpFile = testFolder.resolve("ARandomlyNamedFile"); Files.createFile(tmpFile); @@ -75,7 +73,7 @@ public void testExportingNullDatabaseThrowsNPE(Exporter exportFormat, String nam @ParameterizedTest @MethodSource("exportFormats") - public void testExportingNullEntriesThrowsNPE(Exporter exportFormat, String name, @TempDirectory.TempDir Path testFolder) { + public void testExportingNullEntriesThrowsNPE(Exporter exportFormat, String name, @TempDir Path testFolder) { assertThrows(NullPointerException.class, () -> { Path tmpFile = testFolder.resolve("ARandomlyNamedFile"); Files.createFile(tmpFile); diff --git a/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java b/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java index b1560a3aa65..26c7c61b0f2 100644 --- a/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java +++ b/src/test/java/org/jabref/logic/exporter/GroupSerializerTest.java @@ -22,6 +22,7 @@ import org.jabref.model.groups.SearchGroup; import org.jabref.model.groups.TexGroup; import org.jabref.model.groups.WordKeywordGroup; +import org.jabref.model.metadata.MetaData; import org.jabref.model.util.DummyFileUpdateMonitor; import org.junit.jupiter.api.BeforeEach; @@ -29,31 +30,31 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class GroupSerializerTest { +class GroupSerializerTest { private GroupSerializer groupSerializer; @BeforeEach - public void setUp() throws Exception { + void setUp() throws Exception { groupSerializer = new GroupSerializer(); } @Test - public void serializeSingleAllEntriesGroup() { + void serializeSingleAllEntriesGroup() { AllEntriesGroup group = new AllEntriesGroup(""); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 AllEntriesGroup:"), serialization); } @Test - public void serializeSingleExplicitGroup() { + void serializeSingleExplicitGroup() { ExplicitGroup group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, ','); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 StaticGroup:myExplicitGroup;0;1;;;;"), serialization); } @Test - public void serializeSingleExplicitGroupWithIconAndDescription() { + void serializeSingleExplicitGroupWithIconAndDescription() { ExplicitGroup group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, ','); group.setIconName("test icon"); group.setExpanded(true); @@ -65,63 +66,63 @@ public void serializeSingleExplicitGroupWithIconAndDescription() { @Test // For https://github.com/JabRef/jabref/issues/1681 - public void serializeSingleExplicitGroupWithEscapedSlash() { + void serializeSingleExplicitGroupWithEscapedSlash() { ExplicitGroup group = new ExplicitGroup("B{\\\"{o}}hmer", GroupHierarchyType.INDEPENDENT, ','); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 StaticGroup:B{\\\\\"{o}}hmer;0;1;;;;"), serialization); } @Test - public void serializeSingleSimpleKeywordGroup() { + void serializeSingleSimpleKeywordGroup() { WordKeywordGroup group = new WordKeywordGroup("name", GroupHierarchyType.INDEPENDENT, "keywords", "test", false, ',', false); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 KeywordGroup:name;0;keywords;test;0;0;1;;;;"), serialization); } @Test - public void serializeSingleRegexKeywordGroup() { + void serializeSingleRegexKeywordGroup() { KeywordGroup group = new RegexKeywordGroup("myExplicitGroup", GroupHierarchyType.REFINING, "author", "asdf", false); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 KeywordGroup:myExplicitGroup;1;author;asdf;0;1;1;;;;"), serialization); } @Test - public void serializeSingleSearchGroup() { + void serializeSingleSearchGroup() { SearchGroup group = new SearchGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, "author=harrer", true, true); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 SearchGroup:myExplicitGroup;0;author=harrer;1;1;1;;;;"), serialization); } @Test - public void serializeSingleSearchGroupWithRegex() { + void serializeSingleSearchGroupWithRegex() { SearchGroup group = new SearchGroup("myExplicitGroup", GroupHierarchyType.INCLUDING, "author=\"harrer\"", true, false); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 SearchGroup:myExplicitGroup;2;author=\"harrer\";1;0;1;;;;"), serialization); } @Test - public void serializeSingleAutomaticKeywordGroup() { + void serializeSingleAutomaticKeywordGroup() { AutomaticGroup group = new AutomaticKeywordGroup("myAutomaticGroup", GroupHierarchyType.INDEPENDENT, "keywords", ',', '>'); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 AutomaticKeywordGroup:myAutomaticGroup;0;keywords;,;>;1;;;;"), serialization); } @Test - public void serializeSingleAutomaticPersonGroup() { + void serializeSingleAutomaticPersonGroup() { AutomaticPersonsGroup group = new AutomaticPersonsGroup("myAutomaticGroup", GroupHierarchyType.INDEPENDENT, "authors"); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 AutomaticPersonsGroup:myAutomaticGroup;0;authors;1;;;;"), serialization); } @Test - public void serializeSingleTexGroup() throws Exception { - TexGroup group = new TexGroup("myTexGroup", GroupHierarchyType.INDEPENDENT, Paths.get("path", "To", "File"), new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor()); + void serializeSingleTexGroup() throws Exception { + TexGroup group = TexGroup.createWithoutFileMonitoring("myTexGroup", GroupHierarchyType.INDEPENDENT, Paths.get("path", "To", "File"), new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor(), new MetaData()); List serialization = groupSerializer.serializeTree(GroupTreeNode.fromGroup(group)); assertEquals(Collections.singletonList("0 TexGroup:myTexGroup;0;path/To/File;1;;;;"), serialization); } @Test - public void getTreeAsStringInSimpleTree() throws Exception { + void getTreeAsStringInSimpleTree() throws Exception { GroupTreeNode root = GroupTreeNodeTest.getRoot(); GroupTreeNodeTest.getNodeInSimpleTree(root); @@ -135,7 +136,7 @@ public void getTreeAsStringInSimpleTree() throws Exception { } @Test - public void getTreeAsStringInComplexTree() throws Exception { + void getTreeAsStringInComplexTree() throws Exception { GroupTreeNode root = GroupTreeNodeTest.getRoot(); GroupTreeNodeTest.getNodeInComplexTree(root); diff --git a/src/test/java/org/jabref/logic/exporter/HtmlExportFormatTest.java b/src/test/java/org/jabref/logic/exporter/HtmlExportFormatTest.java index 28067d99bde..3fa8628adba 100644 --- a/src/test/java/org/jabref/logic/exporter/HtmlExportFormatTest.java +++ b/src/test/java/org/jabref/logic/exporter/HtmlExportFormatTest.java @@ -16,14 +16,12 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class HtmlExportFormatTest { public BibDatabaseContext databaseContext; public Charset charset; @@ -55,7 +53,7 @@ public void tearDown() { } @Test - public void emitWellFormedHtml(@TempDirectory.TempDir Path testFolder) throws Exception { + public void emitWellFormedHtml(@TempDir Path testFolder) throws Exception { Path path = testFolder.resolve("ThisIsARandomlyNamedFile"); exportFormat.export(databaseContext, path, charset, entries); List lines = Files.readAllLines(path); diff --git a/src/test/java/org/jabref/logic/exporter/MSBibExportFormatTestFiles.java b/src/test/java/org/jabref/logic/exporter/MSBibExportFormatTestFiles.java index e1de292326a..1a5da06af9b 100644 --- a/src/test/java/org/jabref/logic/exporter/MSBibExportFormatTestFiles.java +++ b/src/test/java/org/jabref/logic/exporter/MSBibExportFormatTestFiles.java @@ -18,10 +18,9 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.junitpioneer.jupiter.TempDirectory; import org.mockito.Answers; import org.xmlunit.builder.Input; import org.xmlunit.builder.Input.Builder; @@ -32,7 +31,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class MSBibExportFormatTestFiles { private static Path resourceDir; @@ -53,7 +51,7 @@ static Stream fileNames() throws IOException, URISyntaxException { } @BeforeEach - void setUp(@TempDirectory.TempDir Path testFolder) throws Exception { + void setUp(@TempDir Path testFolder) throws Exception { databaseContext = new BibDatabaseContext(); charset = StandardCharsets.UTF_8; msBibExportFormat = new MSBibExporter(); diff --git a/src/test/java/org/jabref/logic/exporter/ModsExportFormatTest.java b/src/test/java/org/jabref/logic/exporter/ModsExportFormatTest.java index 2d797d4e8de..65ae6465295 100644 --- a/src/test/java/org/jabref/logic/exporter/ModsExportFormatTest.java +++ b/src/test/java/org/jabref/logic/exporter/ModsExportFormatTest.java @@ -14,14 +14,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class ModsExportFormatTest { public Charset charset; @@ -38,7 +36,7 @@ public void setUp() throws Exception { } @Test - public final void exportForNoEntriesWritesNothing(@TempDirectory.TempDir Path tempFile) throws Exception { + public final void exportForNoEntriesWritesNothing(@TempDir Path tempFile) throws Exception { Path file = tempFile.resolve("ThisIsARandomlyNamedFile"); Files.createFile(file); modsExportFormat.export(databaseContext, tempFile, charset, Collections.emptyList()); diff --git a/src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java b/src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java index 009c9f461ac..3834d7895d9 100644 --- a/src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java +++ b/src/test/java/org/jabref/logic/exporter/ModsExportFormatTestFiles.java @@ -18,10 +18,9 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import org.junitpioneer.jupiter.TempDirectory; import org.mockito.Answers; import org.mockito.Mockito; import org.xmlunit.builder.Input; @@ -33,7 +32,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) public class ModsExportFormatTestFiles { private static Path resourceDir; @@ -57,7 +55,7 @@ public static Stream fileNames() throws Exception { } @BeforeEach - public void setUp(@TempDirectory.TempDir Path testFolder) throws Exception { + public void setUp(@TempDir Path testFolder) throws Exception { databaseContext = new BibDatabaseContext(); charset = StandardCharsets.UTF_8; modsExportFormat = new ModsExporter(); diff --git a/src/test/java/org/jabref/logic/exporter/MsBibExportFormatTest.java b/src/test/java/org/jabref/logic/exporter/MsBibExportFormatTest.java index 103d7c4996b..9ddbe119d73 100644 --- a/src/test/java/org/jabref/logic/exporter/MsBibExportFormatTest.java +++ b/src/test/java/org/jabref/logic/exporter/MsBibExportFormatTest.java @@ -13,12 +13,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; -@ExtendWith(TempDirectory.class) public class MsBibExportFormatTest { public BibDatabaseContext databaseContext; @@ -33,7 +31,7 @@ public void setUp() throws Exception { } @Test - public final void testPerformExportWithNoEntry(@TempDirectory.TempDir Path tempFile) throws IOException, SaveException { + public final void testPerformExportWithNoEntry(@TempDir Path tempFile) throws IOException, SaveException { Path path = tempFile.resolve("ThisIsARandomlyNamedFile"); Files.createFile(path); List entries = Collections.emptyList(); diff --git a/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java b/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java index d06fc91e374..d24b3725624 100644 --- a/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java +++ b/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java @@ -18,15 +18,13 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) public class XmpExporterTest { private Exporter exporter; @@ -48,7 +46,7 @@ public void setUp() { } @Test - public void exportSingleEntry(@TempDirectory.TempDir Path testFolder) throws Exception { + public void exportSingleEntry(@TempDir Path testFolder) throws Exception { Path file = testFolder.resolve("ThisIsARandomlyNamedFile"); Files.createFile(file); @@ -76,7 +74,7 @@ public void exportSingleEntry(@TempDirectory.TempDir Path testFolder) throws Exc } @Test - public void writeMultipleEntriesInASingleFile(@TempDirectory.TempDir Path testFolder) throws Exception { + public void writeMultipleEntriesInASingleFile(@TempDir Path testFolder) throws Exception { Path file = testFolder.resolve("ThisIsARandomlyNamedFile"); Files.createFile(file); @@ -128,7 +126,7 @@ public void writeMultipleEntriesInASingleFile(@TempDirectory.TempDir Path testFo } @Test - public void writeMultipleEntriesInDifferentFiles(@TempDirectory.TempDir Path testFolder) throws Exception { + public void writeMultipleEntriesInDifferentFiles(@TempDir Path testFolder) throws Exception { Path file = testFolder.resolve("split"); Files.createFile(file); @@ -194,7 +192,7 @@ public void writeMultipleEntriesInDifferentFiles(@TempDirectory.TempDir Path tes } @Test - public void exportSingleEntryWithPrivacyFilter(@TempDirectory.TempDir Path testFolder) throws Exception { + public void exportSingleEntryWithPrivacyFilter(@TempDir Path testFolder) throws Exception { when(xmpPreferences.getXmpPrivacyFilter()).thenReturn(Arrays.asList("author")); when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(true); diff --git a/src/test/java/org/jabref/logic/importer/fetcher/DOAJFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/DOAJFetcherTest.java index 77a0a20b925..f49b0e21d17 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/DOAJFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/DOAJFetcherTest.java @@ -9,6 +9,7 @@ import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.testutils.category.FetcherTest; +import org.apache.http.client.utils.URIBuilder; import org.json.JSONObject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -73,4 +74,32 @@ void testBibJSONConverter() { public void searchByEmptyQuery() throws Exception { assertEquals(Collections.emptyList(), fetcher.performSearch("")); } + + @Test + void appendSingleWord() throws Exception { + URIBuilder builder = new URIBuilder("http://example.com/test"); + DOAJFetcher.addPath(builder, "/example"); + assertEquals("http://example.com/test/example", builder.build().toASCIIString()); + } + + @Test + void appendSingleWordWithSlash() throws Exception { + URIBuilder builder = new URIBuilder("http://example.com/test"); + DOAJFetcher.addPath(builder, "/example"); + assertEquals("http://example.com/test/example", builder.build().toASCIIString()); + } + + @Test + void appendSlash() throws Exception { + URIBuilder builder = new URIBuilder("http://example.com/test"); + DOAJFetcher.addPath(builder, "/"); + assertEquals("http://example.com/test", builder.build().toASCIIString()); + } + + @Test + void appendTwoWords() throws Exception { + URIBuilder builder = new URIBuilder("http://example.com/test"); + DOAJFetcher.addPath(builder, "example two"); + assertEquals("http://example.com/test/example%20two", builder.build().toASCIIString()); + } } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java index 54e7ac3944a..bbfa9a6ee8a 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/MedlineFetcherTest.java @@ -27,7 +27,7 @@ public void setUp() { entryWijedasa = new BibEntry(); entryWijedasa.setType(BiblatexEntryTypes.ARTICLE); - entryWijedasa.setField("author", "Wijedasa, Lahiru S and Jauhiainen, Jyrki and Könönen, Mari and Lampela, Maija and Vasander, Harri and Leblanc, Marie-Claire and Evers, Stephanie and Smith, Thomas E L and Yule, Catherine M and Varkkey, Helena and Lupascu, Massimo and Parish, Faizal and Singleton, Ian and Clements, Gopalasamy R and Aziz, Sheema Abdul and Harrison, Mark E and Cheyne, Susan and Anshari, Gusti Z and Meijaard, Erik and Goldstein, Jenny E and Waldron, Susan and Hergoualc'h, Kristell and Dommain, Rene and Frolking, Steve and Evans, Christopher D and Posa, Mary Rose C and Glaser, Paul H and Suryadiputra, Nyoman and Lubis, Reza and Santika, Truly and Padfield, Rory and Kurnianto, Sofyan and Hadisiswoyo, Panut and Lim, Teck Wyn and Page, Susan E and Gauci, Vincent and Van Der Meer, Peter J and Buckland, Helen and Garnier, Fabien and Samuel, Marshall K and Choo, Liza Nuriati Lim Kim and O'Reilly, Patrick and Warren, Matthew and Suksuwan, Surin and Sumarga, Elham and Jain, Anuj and Laurance, William F and Couwenberg, John and Joosten, Hans and Vernimmen, Ronald and Hooijer, Aljosja and Malins, Chris and Cochrane, Mark A and Perumal, Balu and Siegert, Florian and Peh, Kelvin S-H and Comeau, Louis-Pierre and Verchot, Louis and Harvey, Charles F and Cobb, Alex and Jaafar, Zeehan and Wösten, Henk and Manuri, Solichin and Müller, Moritz and Giesen, Wim and Phelps, Jacob and Yong, Ding Li and Silvius, Marcel and Wedeux, Béatrice M M and Hoyt, Alison and Osaki, Mitsuru and Hirano, Takashi and Takahashi, Hidenori and Kohyama, Takashi S and Haraguchi, Akira and Nugroho, Nunung P and Coomes, David A and Quoi, Le Phat and Dohong, Alue and Gunawan, Haris and Gaveau, David L A and Langner, Andreas and Lim, Felix K S and Edwards, David P and Giam, Xingli and Van Der Werf, Guido and Carmenta, Rachel and Verwer, Caspar C and Gibson, Luke and Gandois, Laure and Graham, Laura Linda Bozena and Regalino, Jhanson and Wich, Serge A and Rieley, Jack and Kettridge, Nicholas and Brown, Chloe and Pirard, Romain and Moore, Sam and Capilla, B Ripoll and Ballhorn, Uwe and Ho, Hua Chew and Hoscilo, Agata and Lohberger, Sandra and Evans, Theodore A and Yulianti, Nina and Blackham, Grace and Onrizal and Husson, Simon and Murdiyarso, Daniel and Pangala, Sunita and Cole, Lydia E S and Tacconi, Luca and Segah, Hendrik and Tonoto, Prayoto and Lee, Janice S H and Schmilewski, Gerald and Wulffraat, Stephan and Putra, Erianto Indra and Cattau, Megan E and Clymo, R S and Morrison, Ross and Mujahid, Aazani and Miettinen, Jukka and Liew, Soo Chin and Valpola, Samu and Wilson, David and D'Arcy, Laura and Gerding, Michiel and Sundari, Siti and Thornton, Sara A and Kalisz, Barbara and Chapman, Stephen J and Su, Ahmad Suhaizi Mat and Basuki, Imam and Itoh, Masayuki and Traeholt, Carl and Sloan, Sean and Sayok, Alexander K and Andersen, Roxane"); + entryWijedasa.setField("author", "Wijedasa, Lahiru S. and Jauhiainen, Jyrki and Könönen, Mari and Lampela, Maija and Vasander, Harri and Leblanc, Marie-Claire and Evers, Stephanie and Smith, Thomas E. L. and Yule, Catherine M. and Varkkey, Helena and Lupascu, Massimo and Parish, Faizal and Singleton, Ian and Clements, Gopalasamy R. and Aziz, Sheema Abdul and Harrison, Mark E. and Cheyne, Susan and Anshari, Gusti Z. and Meijaard, Erik and Goldstein, Jenny E. and Waldron, Susan and Hergoualc'h, Kristell and Dommain, Rene and Frolking, Steve and Evans, Christopher D. and Posa, Mary Rose C. and Glaser, Paul H. and Suryadiputra, Nyoman and Lubis, Reza and Santika, Truly and Padfield, Rory and Kurnianto, Sofyan and Hadisiswoyo, Panut and Lim, Teck Wyn and Page, Susan E. and Gauci, Vincent and Van Der Meer, Peter J. and Buckland, Helen and Garnier, Fabien and Samuel, Marshall K. and Choo, Liza Nuriati Lim Kim and O'Reilly, Patrick and Warren, Matthew and Suksuwan, Surin and Sumarga, Elham and Jain, Anuj and Laurance, William F. and Couwenberg, John and Joosten, Hans and Vernimmen, Ronald and Hooijer, Aljosja and Malins, Chris and Cochrane, Mark A. and Perumal, Balu and Siegert, Florian and Peh, Kelvin S.-H. and Comeau, Louis-Pierre and Verchot, Louis and Harvey, Charles F. and Cobb, Alex and Jaafar, Zeehan and Wösten, Henk and Manuri, Solichin and Müller, Moritz and Giesen, Wim and Phelps, Jacob and Yong, Ding Li and Silvius, Marcel and Wedeux, Béatrice M. M. and Hoyt, Alison and Osaki, Mitsuru and Hirano, Takashi and Takahashi, Hidenori and Kohyama, Takashi S. and Haraguchi, Akira and Nugroho, Nunung P. and Coomes, David A. and Quoi, Le Phat and Dohong, Alue and Gunawan, Haris and Gaveau, David L. A. and Langner, Andreas and Lim, Felix K. S. and Edwards, David P. and Giam, Xingli and Van Der Werf, Guido and Carmenta, Rachel and Verwer, Caspar C. and Gibson, Luke and Gandois, Laure and Graham, Laura Linda Bozena and Regalino, Jhanson and Wich, Serge A. and Rieley, Jack and Kettridge, Nicholas and Brown, Chloe and Pirard, Romain and Moore, Sam and Capilla, B. Ripoll and Ballhorn, Uwe and Ho, Hua Chew and Hoscilo, Agata and Lohberger, Sandra and Evans, Theodore A. and Yulianti, Nina and Blackham, Grace and Onrizal and Husson, Simon and Murdiyarso, Daniel and Pangala, Sunita and Cole, Lydia E. S. and Tacconi, Luca and Segah, Hendrik and Tonoto, Prayoto and Lee, Janice S. H. and Schmilewski, Gerald and Wulffraat, Stephan and Putra, Erianto Indra and Cattau, Megan E. and Clymo, R. S. and Morrison, Ross and Mujahid, Aazani and Miettinen, Jukka and Liew, Soo Chin and Valpola, Samu and Wilson, David and D'Arcy, Laura and Gerding, Michiel and Sundari, Siti and Thornton, Sara A. and Kalisz, Barbara and Chapman, Stephen J. and Su, Ahmad Suhaizi Mat and Basuki, Imam and Itoh, Masayuki and Traeholt, Carl and Sloan, Sean and Sayok, Alexander K. and Andersen, Roxane"); entryWijedasa.setField("country", "England"); entryWijedasa.setField("doi", "10.1111/gcb.13516"); entryWijedasa.setField("issn", "1365-2486"); @@ -66,7 +66,7 @@ public void setUp() { entryEndharti.setField("pmid", "27670445"); entryEndharti.setField("pubmodel", "Electronic"); entryEndharti.setField("pubstatus", "epublish"); - entryEndharti.setField("revised", "2017-02-20"); + entryEndharti.setField("revised", "2018-11-13"); entryEndharti.setField("volume", "16"); entryEndharti.setField("year", "2016"); @@ -110,7 +110,7 @@ public void setUp() { bibEntrySari.setField("keywords", "Antibodies, Protozoan; Antibodies, Viral, immunology; Coinfection, epidemiology, immunology; Female; HIV Infections, epidemiology; HTLV-I Antibodies, immunology; HTLV-I Infections, epidemiology, immunology; HTLV-II Antibodies, immunology; HTLV-II Infections, epidemiology, immunology; Hepatitis Antibodies, immunology; Hepatitis B Antibodies, immunology; Hepatitis C Antibodies, immunology; Hepatitis Delta Virus, immunology; Hepatitis, Viral, Human, epidemiology, immunology; Humans; Immunoglobulin G, immunology; Immunoglobulin M, immunology; Indonesia, epidemiology; Male; Prisoners; Seroepidemiologic Studies; Toxoplasma, immunology; Toxoplasmosis, epidemiology, immunology"); bibEntrySari.setField("month", "#nov#"); bibEntrySari.setField("pubstatus", "ppublish"); - bibEntrySari.setField("revised", "2016-02-12"); + bibEntrySari.setField("revised", "2018-12-02"); bibEntrySari.setField("nlm-id", "0266303"); bibEntrySari.setField("owner", "NLM"); bibEntrySari.setField("pages", "977--985"); diff --git a/src/test/java/org/jabref/logic/importer/fileformat/BibtexParserTest.java b/src/test/java/org/jabref/logic/importer/fileformat/BibtexParserTest.java index 98c3a8cc2f8..04fca15aff8 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/BibtexParserTest.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/BibtexParserTest.java @@ -57,7 +57,7 @@ class BibtexParserTest { private ImportFormatPreferences importFormatPreferences; private BibtexParser parser; - private FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); + private final FileUpdateMonitor fileMonitor = new DummyFileUpdateMonitor(); @BeforeEach void setUp() { @@ -327,7 +327,7 @@ void parseRecognizesEntryWithAtInField() throws IOException { List parsed = result.getDatabase().getEntries(); BibEntry expected = new BibEntry(BibtexEntryTypes.ARTICLE).withField(BibEntry.KEY_FIELD, "test") - .withField("author", "Ed von T@st"); + .withField("author", "Ed von T@st"); assertEquals(Collections.singletonList(expected), parsed); } @@ -1338,7 +1338,7 @@ void integrationTestSaveOrderConfig() throws IOException { Optional saveOrderConfig = result.getMetaData().getSaveOrderConfig(); - assertEquals(new SaveOrderConfig(false, new SaveOrderConfig.SortCriterion("author", false), + assertEquals(new SaveOrderConfig(false, true, new SaveOrderConfig.SortCriterion("author", false), new SaveOrderConfig.SortCriterion("year", true), new SaveOrderConfig.SortCriterion("abstract", false)), saveOrderConfig.get()); } @@ -1474,10 +1474,12 @@ void parseDoesNotRecognizeDatabaseIDasUserComment() throws Exception { void integrationTestFileDirectories() throws IOException { ParserResult result = parser.parse( new StringReader("@comment{jabref-meta: fileDirectory:\\\\Literature\\\\;}" - + "@comment{jabref-meta: fileDirectory-defaultOwner-user:D:\\\\Documents;}")); + + "@comment{jabref-meta: fileDirectory-defaultOwner-user:D:\\\\Documents;}" + + "@comment{jabref-meta: fileDirectoryLatex-defaultOwner-user:D:\\\\Latex;}")); assertEquals("\\Literature\\", result.getMetaData().getDefaultFileDirectory().get()); assertEquals("D:\\Documents", result.getMetaData().getUserFileDirectory("defaultOwner-user").get()); + assertEquals("D:\\Latex", result.getMetaData().getLaTexFileDirectory("defaultOwner-user").get().toString()); } @Test diff --git a/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTest.java b/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTest.java index b82795865d6..e2e88675e11 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTest.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTest.java @@ -11,6 +11,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; +import org.jabref.model.entry.LinkedFile; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,47 +19,47 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -public class PdfContentImporterTest { +class PdfContentImporterTest { private PdfContentImporter importer; @BeforeEach - public void setUp() { + void setUp() { importer = new PdfContentImporter(mock(ImportFormatPreferences.class)); } @Test - public void testsGetExtensions() { + void testsGetExtensions() { assertEquals(StandardFileType.PDF, importer.getFileType()); } @Test - public void testGetDescription() { + void testGetDescription() { assertEquals( "PdfContentImporter parses data of the first page of the PDF and creates a BibTeX entry. Currently, Springer and IEEE formats are supported.", importer.getDescription()); } @Test - public void doesNotHandleEncryptedPdfs() throws Exception { + void doesNotHandleEncryptedPdfs() throws Exception { Path file = Paths.get(PdfContentImporter.class.getResource("/pdfs/encrypted.pdf").toURI()); List result = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries(); assertEquals(Collections.emptyList(), result); } @Test - public void importTwiceWorksAsExpected() throws Exception { + void importTwiceWorksAsExpected() throws Exception { Path file = Paths.get(PdfContentImporter.class.getResource("/pdfs/minimal.pdf").toURI()); List result = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries(); BibEntry expected = new BibEntry(BibtexEntryTypes.INPROCEEDINGS); expected.setField(FieldName.AUTHOR, "1 "); expected.setField(FieldName.TITLE, "Hello World"); + expected.setFiles(Collections.singletonList(new LinkedFile("", file.toAbsolutePath(), "PDF"))); List resultSecondImport = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries(); assertEquals(Collections.singletonList(expected), result); assertEquals(Collections.singletonList(expected), resultSecondImport); - } } diff --git a/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java b/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java index 7dc4cef6f26..55aa1c59709 100644 --- a/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java +++ b/src/test/java/org/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java @@ -6,12 +6,13 @@ import org.jabref.logic.importer.ImportFormatPreferences; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import static org.mockito.Mockito.mock; -public class PdfContentImporterTestFiles { +class PdfContentImporterTestFiles { private static final String FILE_ENDING = ".pdf"; @@ -23,13 +24,14 @@ private static Stream fileNames() throws IOException { @ParameterizedTest @MethodSource("fileNames") - public void testIsRecognizedFormat(String fileName) throws IOException { + void testIsRecognizedFormat(String fileName) throws IOException { ImporterTestEngine.testIsRecognizedFormat(new PdfContentImporter(mock(ImportFormatPreferences.class)), fileName); } @ParameterizedTest @MethodSource("fileNames") - public void testImportEntries(String fileName) throws Exception { + @Disabled("bib file does not contain linked file") + void testImportEntries(String fileName) throws Exception { ImporterTestEngine.testImportEntries(new PdfContentImporter(mock(ImportFormatPreferences.class)), fileName, FILE_ENDING); } } diff --git a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java index 765f93ddcfe..640644dec0d 100644 --- a/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java +++ b/src/test/java/org/jabref/logic/importer/util/GroupsParserTest.java @@ -17,6 +17,7 @@ import org.jabref.model.groups.GroupHierarchyType; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.groups.TexGroup; +import org.jabref.model.metadata.MetaData; import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.model.util.FileUpdateMonitor; @@ -26,44 +27,46 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class GroupsParserTest { +class GroupsParserTest { private FileUpdateMonitor fileMonitor; + private MetaData metaData; @BeforeEach - public void setUp() throws Exception { + void setUp() throws Exception { fileMonitor = new DummyFileUpdateMonitor(); + metaData = new MetaData(); } @Test // For https://github.com/JabRef/jabref/issues/1681 - public void fromStringParsesExplicitGroupWithEscapedCharacterInName() throws Exception { + void fromStringParsesExplicitGroupWithEscapedCharacterInName() throws Exception { ExplicitGroup expected = new ExplicitGroup("B{\\\"{o}}hmer", GroupHierarchyType.INDEPENDENT, ','); - AbstractGroup parsed = GroupsParser.fromString("ExplicitGroup:B{\\\\\"{o}}hmer;0;", ',', fileMonitor); + AbstractGroup parsed = GroupsParser.fromString("ExplicitGroup:B{\\\\\"{o}}hmer;0;", ',', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void keywordDelimiterThatNeedsToBeEscaped() throws Exception { + void keywordDelimiterThatNeedsToBeEscaped() throws Exception { AutomaticGroup expected = new AutomaticKeywordGroup("group1", GroupHierarchyType.INDEPENDENT, "keywords", ';', '>'); - AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;\\;;>;1;;;;;", ';', fileMonitor); + AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;\\;;>;1;;;;;", ';', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void hierarchicalDelimiterThatNeedsToBeEscaped() throws Exception { + void hierarchicalDelimiterThatNeedsToBeEscaped() throws Exception { AutomaticGroup expected = new AutomaticKeywordGroup("group1", GroupHierarchyType.INDEPENDENT, "keywords", ',', ';'); - AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;,;\\;;1;;;;;", ';', fileMonitor); + AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:group1;0;keywords;,;\\;;1;;;;;", ';', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void fromStringThrowsParseExceptionForNotEscapedGroupName() throws Exception { - assertThrows(ParseException.class, () -> GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor)); + void fromStringThrowsParseExceptionForNotEscapedGroupName() throws Exception { + assertThrows(ParseException.class, () -> GroupsParser.fromString("ExplicitGroup:slit\\\\;0\\;mertsch_slit2_2007\\;;", ',', fileMonitor, metaData)); } @Test - public void testImportSubGroups() throws Exception { + void testImportSubGroups() throws Exception { List orderedData = Arrays.asList("0 AllEntriesGroup:", "1 ExplicitGroup:1;0;", "2 ExplicitGroup:2;0;", "0 ExplicitGroup:3;0;"); @@ -85,45 +88,45 @@ public void testImportSubGroups() throws Exception { AbstractGroup thirdSubGrpLvl1 = new ExplicitGroup("3", GroupHierarchyType.INDEPENDENT, ','); rootNode.addSubgroup(thirdSubGrpLvl1); - GroupTreeNode parsedNode = GroupsParser.importGroups(orderedData, ',', fileMonitor); + GroupTreeNode parsedNode = GroupsParser.importGroups(orderedData, ',', fileMonitor, metaData); assertEquals(rootNode.getChildren(), parsedNode.getChildren()); } @Test - public void fromStringParsesExplicitGroupWithIconAndDescription() throws Exception { + void fromStringParsesExplicitGroupWithIconAndDescription() throws Exception { ExplicitGroup expected = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, ','); expected.setIconName("test icon"); expected.setExpanded(true); expected.setColor(Color.ALICEBLUE); expected.setDescription("test description"); - AbstractGroup parsed = GroupsParser.fromString("StaticGroup:myExplicitGroup;0;1;0xf0f8ffff;test icon;test description;", ',', fileMonitor); + AbstractGroup parsed = GroupsParser.fromString("StaticGroup:myExplicitGroup;0;1;0xf0f8ffff;test icon;test description;", ',', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void fromStringParsesAutomaticKeywordGroup() throws Exception { + void fromStringParsesAutomaticKeywordGroup() throws Exception { AutomaticGroup expected = new AutomaticKeywordGroup("myAutomaticGroup", GroupHierarchyType.INDEPENDENT, "keywords", ',', '>'); - AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:myAutomaticGroup;0;keywords;,;>;1;;;;", ',', fileMonitor); + AbstractGroup parsed = GroupsParser.fromString("AutomaticKeywordGroup:myAutomaticGroup;0;keywords;,;>;1;;;;", ',', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void fromStringParsesAutomaticPersonGroup() throws Exception { + void fromStringParsesAutomaticPersonGroup() throws Exception { AutomaticPersonsGroup expected = new AutomaticPersonsGroup("myAutomaticGroup", GroupHierarchyType.INDEPENDENT, "authors"); - AbstractGroup parsed = GroupsParser.fromString("AutomaticPersonsGroup:myAutomaticGroup;0;authors;1;;;;", ',', fileMonitor); + AbstractGroup parsed = GroupsParser.fromString("AutomaticPersonsGroup:myAutomaticGroup;0;authors;1;;;;", ',', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void fromStringParsesTexGroup() throws Exception { - TexGroup expected = new TexGroup("myTexGroup", GroupHierarchyType.INDEPENDENT, Paths.get("path", "To", "File"), new DefaultAuxParser(new BibDatabase()), fileMonitor); - AbstractGroup parsed = GroupsParser.fromString("TexGroup:myTexGroup;0;path/To/File;1;;;;", ',', fileMonitor); + void fromStringParsesTexGroup() throws Exception { + TexGroup expected = TexGroup.createWithoutFileMonitoring("myTexGroup", GroupHierarchyType.INDEPENDENT, Paths.get("path", "To", "File"), new DefaultAuxParser(new BibDatabase()), fileMonitor, metaData); + AbstractGroup parsed = GroupsParser.fromString("TexGroup:myTexGroup;0;path/To/File;1;;;;", ',', fileMonitor, metaData); assertEquals(expected, parsed); } @Test - public void fromStringUnknownGroupThrowsException() throws Exception { - assertThrows(ParseException.class, () -> GroupsParser.fromString("0 UnknownGroup:myUnknownGroup;0;;1;;;;", ',', fileMonitor)); + void fromStringUnknownGroupThrowsException() throws Exception { + assertThrows(ParseException.class, () -> GroupsParser.fromString("0 UnknownGroup:myUnknownGroup;0;;1;;;;", ',', fileMonitor, metaData)); } } diff --git a/src/test/java/org/jabref/logic/integrity/IntegrityCheckTest.java b/src/test/java/org/jabref/logic/integrity/IntegrityCheckTest.java index 54a1d715e99..02bf279d838 100644 --- a/src/test/java/org/jabref/logic/integrity/IntegrityCheckTest.java +++ b/src/test/java/org/jabref/logic/integrity/IntegrityCheckTest.java @@ -23,8 +23,7 @@ import org.jabref.model.metadata.MetaData; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mockito; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,7 +31,6 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) class IntegrityCheckTest { @Test @@ -86,6 +84,7 @@ void testEditionChecks() { withMode(createContext("edition", "Third, revised and expanded edition"), BibDatabaseMode.BIBLATEX)); assertCorrect(withMode(createContext("edition", "Edition 2000"), BibDatabaseMode.BIBLATEX)); assertWrong(withMode(createContext("edition", "2nd"), BibDatabaseMode.BIBLATEX)); + assertWrong(createContext("edition", "1")); } @Test @@ -220,7 +219,7 @@ void testFileChecks() { } @Test - void fileCheckFindsFilesRelativeToBibFile(@TempDirectory.TempDir Path testFolder) throws IOException { + void fileCheckFindsFilesRelativeToBibFile(@TempDir Path testFolder) throws IOException { Path bibFile = testFolder.resolve("lit.bib"); Files.createFile(bibFile); Path pdfFile = testFolder.resolve("file.pdf"); diff --git a/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java b/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java index 6f8aa2c15de..7e8ef1db2d9 100644 --- a/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java +++ b/src/test/java/org/jabref/logic/l10n/LocalizationConsistencyTest.java @@ -112,8 +112,8 @@ void findMissingLocalizationKeys() throws IOException { "DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH LANGUAGE FILE\n" + "PASTE THESE INTO THE ENGLISH LANGUAGE FILE\n" + missingKeys.parallelStream() - .map(key -> String.format("\n%s=%s\n", key.getKey(), key.getKey().replaceAll("\\\\ ", " "))) - .collect(Collectors.joining("\n"))); + .map(key -> String.format("%s=%s", key.getKey(), key.getKey().replaceAll("\\\\ ", " "))) + .collect(Collectors.joining("\n", "\n", "\n"))); } @Test diff --git a/src/test/java/org/jabref/logic/layout/LayoutTest.java b/src/test/java/org/jabref/logic/layout/LayoutTest.java index 1e737784520..34e04b157e3 100644 --- a/src/test/java/org/jabref/logic/layout/LayoutTest.java +++ b/src/test/java/org/jabref/logic/layout/LayoutTest.java @@ -6,6 +6,7 @@ import java.util.Collections; import org.jabref.logic.layout.format.FileLinkPreferences; +import org.jabref.logic.layout.format.NameFormatterPreferences; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.CustomEntryType; @@ -38,7 +39,7 @@ private String layout(String layout, BibEntry entry) throws IOException { @Test void entryTypeForUnknown() throws IOException { - BibEntry entry = new BibEntry(new CustomEntryType("unknown","required","optional")).withField("author", "test"); + BibEntry entry = new BibEntry(new CustomEntryType("unknown", "required", "optional")).withField("author", "test"); assertEquals("Unknown", layout("\\bibtextype", entry)); } @@ -98,8 +99,10 @@ void HTMLCharsWithDotlessIAndTiled() throws IOException { layoutText); } + /** + * Test for http://discourse.jabref.org/t/the-wrapfilelinks-formatter/172 (the example in the help files) + */ @Test - // Test for http://discourse.jabref.org/t/the-wrapfilelinks-formatter/172 (the example in the help files) void wrapFileLinksExpandFile() throws IOException { when(layoutFormatterPreferences.getFileLinkPreferences()).thenReturn( new FileLinkPreferences(Collections.emptyList(), Collections.singletonList("src/test/resources/pdfs/"))); @@ -121,4 +124,15 @@ void expandCommandIfTerminatedByMinus() throws IOException { assertEquals("2-th ed.-", layoutText); } + + @Test + void customNameFormatter() throws IOException { + when(layoutFormatterPreferences.getNameFormatterPreferences()).thenReturn( + new NameFormatterPreferences(Collections.singletonList("DCA"), Collections.singletonList("1@*@{ll}@@2@1..1@{ff}{ll}@2..2@ and {ff}{l}@@*@*@more"))); + BibEntry entry = new BibEntry(BibtexEntryTypes.ARTICLE).withField("author", "Joe Doe and Mary Jane"); + + String layoutText = layout("\\begin{author}\\format[DCA]{\\author}\\end{author}", entry); + + assertEquals("JoeDoe and MaryJ", layoutText); + } } diff --git a/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java b/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java index cbb37c47408..8736b6542e1 100644 --- a/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java +++ b/src/test/java/org/jabref/logic/msbib/MsBibAuthorTest.java @@ -44,4 +44,11 @@ public void testGetLastName() { MsBibAuthor msBibAuthor = new MsBibAuthor(author); assertEquals("Bach", msBibAuthor.getLastName()); } + + @Test + public void testGetVonAndLastName() { + Author author = new Author("John", null, "von", "Neumann", null); + MsBibAuthor msBibAuthor = new MsBibAuthor(author); + assertEquals("von Neumann", msBibAuthor.getLastName()); + } } diff --git a/src/test/java/org/jabref/logic/net/URLUtilTest.java b/src/test/java/org/jabref/logic/net/URLUtilTest.java index 01f181eb465..6a6cfc12972 100644 --- a/src/test/java/org/jabref/logic/net/URLUtilTest.java +++ b/src/test/java/org/jabref/logic/net/URLUtilTest.java @@ -1,6 +1,7 @@ package org.jabref.logic.net; -import org.apache.http.client.utils.URIBuilder; +import org.jabref.gui.fieldeditors.URLUtil; + import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -73,31 +74,4 @@ void isURLshouldRejectInvalidURL() { assertFalse(URLUtil.isURL("google.com")); } - @Test - void appendSingleWord() throws Exception { - URIBuilder builder = new URIBuilder("http://example.com/test"); - URLUtil.addPath(builder, "/example"); - assertEquals("http://example.com/test/example", builder.build().toASCIIString()); - } - - @Test - void appendSingleWordWithSlash() throws Exception { - URIBuilder builder = new URIBuilder("http://example.com/test"); - URLUtil.addPath(builder, "/example"); - assertEquals("http://example.com/test/example", builder.build().toASCIIString()); - } - - @Test - void appendSlash() throws Exception { - URIBuilder builder = new URIBuilder("http://example.com/test"); - URLUtil.addPath(builder, "/"); - assertEquals("http://example.com/test", builder.build().toASCIIString()); - } - - @Test - void appendTwoWords() throws Exception { - URIBuilder builder = new URIBuilder("http://example.com/test"); - URLUtil.addPath(builder, "example two"); - assertEquals("http://example.com/test/example%20two", builder.build().toASCIIString()); - } } diff --git a/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java b/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java index 0ad5b9bca30..6a34b57f78a 100644 --- a/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java +++ b/src/test/java/org/jabref/logic/pdf/EntryAnnotationImporterTest.java @@ -24,7 +24,7 @@ public class EntryAnnotationImporterTest { private final BibDatabaseContext databaseContext = mock(BibDatabaseContext.class); - private final BibEntry entry = new BibEntry(new CustomEntryType("EntryKey","required","optional")); + private final BibEntry entry = new BibEntry(new CustomEntryType("EntryKey", "required", "optional")); @BeforeEach public void setUp() { diff --git a/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsListTest.java b/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsListTest.java index c8fbdf7f7e6..54109db5c86 100644 --- a/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsListTest.java +++ b/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsListTest.java @@ -8,21 +8,19 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -@ExtendWith(TempDirectory.class) public class ProtectedTermsListTest { private ProtectedTermsList internalList; private ProtectedTermsList externalList; @BeforeEach - public void setUp(@TempDirectory.TempDir Path temporaryFolder) throws IOException { + public void setUp(@TempDir Path temporaryFolder) throws IOException { Path path = temporaryFolder.resolve("ThisIsARandomlyNamedFile"); Files.createFile(path); String tempFileName = path.toString(); diff --git a/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsLoaderTest.java b/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsLoaderTest.java index 0cc24dc3b8a..b08c1c3546d 100644 --- a/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsLoaderTest.java +++ b/src/test/java/org/jabref/logic/protectedterms/ProtectedTermsLoaderTest.java @@ -14,14 +14,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -@ExtendWith(TempDirectory.class) class ProtectedTermsLoaderTest { private ProtectedTermsLoader loader; @@ -166,7 +164,7 @@ void testDoNotLoadTheSameInternalListTwice() { } @Test - void testAddNewTermListAddsList(@TempDirectory.TempDir Path tempDir) { + void testAddNewTermListAddsList(@TempDir Path tempDir) { ProtectedTermsLoader localLoader = new ProtectedTermsLoader( new ProtectedTermsPreferences(Collections.emptyList(), Collections.emptyList(), @@ -176,7 +174,7 @@ void testAddNewTermListAddsList(@TempDirectory.TempDir Path tempDir) { } @Test - void testAddNewTermListNewListInList(@TempDirectory.TempDir Path tempDir) { + void testAddNewTermListNewListInList(@TempDir Path tempDir) { ProtectedTermsLoader localLoader = new ProtectedTermsLoader( new ProtectedTermsPreferences(Collections.emptyList(), Collections.emptyList(), @@ -187,7 +185,7 @@ void testAddNewTermListNewListInList(@TempDirectory.TempDir Path tempDir) { } @Test - void testRemoveTermList(@TempDirectory.TempDir Path tempDir) { + void testRemoveTermList(@TempDir Path tempDir) { ProtectedTermsLoader localLoader = new ProtectedTermsLoader( new ProtectedTermsPreferences(Collections.emptyList(), Collections.emptyList(), @@ -197,7 +195,7 @@ void testRemoveTermList(@TempDirectory.TempDir Path tempDir) { } @Test - void testRemoveTermListReduceTheCount(@TempDirectory.TempDir Path tempDir) { + void testRemoveTermListReduceTheCount(@TempDir Path tempDir) { ProtectedTermsLoader localLoader = new ProtectedTermsLoader( new ProtectedTermsPreferences(Collections.emptyList(), Collections.emptyList(), @@ -209,7 +207,7 @@ void testRemoveTermListReduceTheCount(@TempDirectory.TempDir Path tempDir) { } @Test - void testAddNewTermListSetsCorrectDescription(@TempDirectory.TempDir Path tempDir) { + void testAddNewTermListSetsCorrectDescription(@TempDir Path tempDir) { ProtectedTermsLoader localLoader = new ProtectedTermsLoader( new ProtectedTermsPreferences(Collections.emptyList(), Collections.emptyList(), diff --git a/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java b/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java index 1d84949752b..088ff3c9988 100644 --- a/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java +++ b/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java @@ -113,6 +113,24 @@ void testUpdateEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProce assertEquals(expectedEntry, actualEntryOptional.get()); } + @ParameterizedTest + @MethodSource("getTestingDatabaseSystems") + void testGetEntriesByIdList(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws OfflineLockException, SQLException { + dbmsProcessor.setupSharedDatabase(); + BibEntry firstEntry = getBibEntryExample(); + firstEntry.setId("1"); + BibEntry secondEntry = getBibEntryExample(); + secondEntry.setId("2"); + + dbmsProcessor.insertEntry(firstEntry); + dbmsProcessor.insertEntry(secondEntry); + + List sharedEntriesByIdList = dbmsProcessor.getSharedEntries(Arrays.asList(1, 2)); + + assertEquals(firstEntry.getId(), sharedEntriesByIdList.get(0).getId()); + assertEquals(secondEntry.getId(), sharedEntriesByIdList.get(1).getId()); + } + @ParameterizedTest @MethodSource("getTestingDatabaseSystems") void testUpdateNewerEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws OfflineLockException, SQLException { diff --git a/src/test/java/org/jabref/logic/util/io/CiteKeyBasedFileFinderTest.java b/src/test/java/org/jabref/logic/util/io/CiteKeyBasedFileFinderTest.java index 70c8ea51941..67e5147665e 100644 --- a/src/test/java/org/jabref/logic/util/io/CiteKeyBasedFileFinderTest.java +++ b/src/test/java/org/jabref/logic/util/io/CiteKeyBasedFileFinderTest.java @@ -12,12 +12,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; -@ExtendWith(TempDirectory.class) class CiteKeyBasedFileFinderTest { private BibEntry entry; @@ -28,7 +26,7 @@ class CiteKeyBasedFileFinderTest { private Path pdfFile; @BeforeEach - void setUp(@TempDirectory.TempDir Path temporaryFolder) throws IOException { + void setUp(@TempDir Path temporaryFolder) throws IOException { entry = new BibEntry(BibtexEntryTypes.ARTICLE); entry.setCiteKey("HipKro03"); diff --git a/src/test/java/org/jabref/logic/util/io/FileUtilTest.java b/src/test/java/org/jabref/logic/util/io/FileUtilTest.java index 4103e8b7d23..386ab268e08 100644 --- a/src/test/java/org/jabref/logic/util/io/FileUtilTest.java +++ b/src/test/java/org/jabref/logic/util/io/FileUtilTest.java @@ -18,8 +18,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -29,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -@ExtendWith(TempDirectory.class) class FileUtilTest { private final Path nonExistingTestPath = Paths.get("nonExistingTestPath"); private Path existingTestFile; @@ -38,7 +36,7 @@ class FileUtilTest { private Path rootDir; @BeforeEach - void setUpViewModel(@TempDirectory.TempDir Path temporaryFolder) throws IOException { + void setUpViewModel(@TempDir Path temporaryFolder) throws IOException { rootDir = temporaryFolder; Path subDir = rootDir.resolve("1"); Files.createDirectory(subDir); @@ -322,7 +320,7 @@ void testRenameFileWithFromFileExistAndOtherToFileExist() { } @Test - void testRenameFileSuccessful(@TempDirectory.TempDir Path otherTemporaryFolder) { + void testRenameFileSuccessful(@TempDir Path otherTemporaryFolder) { // Be careful. This "otherTemporaryFolder" is the same as the "temporaryFolder" // in the @BeforeEach method. Path temp = Paths.get(otherTemporaryFolder.resolve("123").toString()); diff --git a/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java b/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java index 92160685052..add59fee6d8 100644 --- a/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java +++ b/src/test/java/org/jabref/logic/xmp/XmpUtilReaderTest.java @@ -5,6 +5,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -13,6 +14,7 @@ import org.jabref.logic.importer.ParseException; import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.util.DummyFileUpdateMonitor; import com.google.common.io.Resources; @@ -69,11 +71,16 @@ void testReadArticleDublinCoreReadRawXmp() throws IOException, URISyntaxExceptio */ @Test void testReadArticleDublinCoreReadXmp() throws IOException, URISyntaxException, ParseException { - List entries = XmpUtilReader.readXmp(Paths.get(XmpUtilShared.class.getResource("article_dublinCore.pdf").toURI()), xmpPreferences); + Path pathPdf = Paths.get(XmpUtilShared.class.getResource("article_dublinCore.pdf").toURI()); + List entries = XmpUtilReader.readXmp(pathPdf, xmpPreferences); BibEntry entry = entries.get(0); String bibString = Resources.toString(XmpUtilShared.class.getResource("article_dublinCore.bib"), StandardCharsets.UTF_8); Optional entryFromBibFile = parser.parseSingleEntry(bibString); + entryFromBibFile.get().setFiles(Arrays.asList( + new LinkedFile("", "paper.pdf", "PDF"), + new LinkedFile("", pathPdf.toAbsolutePath().toString(), "PDF")) + ); assertEquals(entryFromBibFile.get(), entry); } @@ -92,10 +99,14 @@ void testReadEmtpyMetadata() throws IOException, URISyntaxException { */ @Test void testReadPDMetadata() throws IOException, URISyntaxException, ParseException { - List entries = XmpUtilReader.readXmp(Paths.get(XmpUtilShared.class.getResource("PD_metadata.pdf").toURI()), xmpPreferences); + Path pathPdf = Paths.get(XmpUtilShared.class.getResource("PD_metadata.pdf").toURI()); + List entries = XmpUtilReader.readXmp(pathPdf, xmpPreferences); String bibString = Resources.toString(XmpUtilShared.class.getResource("PD_metadata.bib"), StandardCharsets.UTF_8); Optional entryFromBibFile = parser.parseSingleEntry(bibString); + entryFromBibFile.get().setFiles(Collections.singletonList( + new LinkedFile("", pathPdf.toAbsolutePath().toString(), "PDF")) + ); assertEquals(entryFromBibFile.get(), entries.get(0)); } diff --git a/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java b/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java index f3d57c6bfae..e2ddf418961 100644 --- a/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java +++ b/src/test/java/org/jabref/logic/xmp/XmpUtilWriterTest.java @@ -9,20 +9,19 @@ import javax.xml.transform.TransformerException; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.FieldName; import org.jabref.model.entry.Month; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junitpioneer.jupiter.TempDirectory; +import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@ExtendWith(TempDirectory.class) class XmpUtilWriterTest { private static BibEntry olly2018; @@ -31,7 +30,6 @@ class XmpUtilWriterTest { private XmpPreferences xmpPreferences; private void initBibEntries() { - olly2018 = new BibEntry(); olly2018.setType("article"); olly2018.setCiteKey("Olly2018"); @@ -80,7 +78,6 @@ private void initBibEntries() { */ @BeforeEach void setUp() { - xmpPreferences = mock(XmpPreferences.class); // The code assumes privacy filters to be off when(xmpPreferences.isUseXMPPrivacyFilter()).thenReturn(false); @@ -94,8 +91,7 @@ void setUp() { * Test for writing a PDF file with a single DublinCore metadata entry. */ @Test - void testWriteXmp(@TempDirectory.TempDir Path tempDir) throws IOException, TransformerException { - + void testWriteXmp(@TempDir Path tempDir) throws IOException, TransformerException { Path pdfFile = this.createDefaultFile("JabRef_writeSingle.pdf", tempDir); // read a bib entry from the tests before @@ -103,12 +99,13 @@ void testWriteXmp(@TempDirectory.TempDir Path tempDir) throws IOException, Trans entry.setCiteKey("WriteXMPTest"); entry.setId("ID4711"); - // write the changed bib entry to the create PDF + // write the changed bib entry to the PDF XmpUtilWriter.writeXmp(pdfFile.toAbsolutePath().toString(), entry, null, xmpPreferences); // read entry again List entriesWritten = XmpUtilReader.readXmp(pdfFile.toAbsolutePath().toString(), xmpPreferences); BibEntry entryWritten = entriesWritten.get(0); + entryWritten.clearField(FieldName.FILE); // compare the two entries assertEquals(entry, entryWritten); @@ -118,8 +115,7 @@ void testWriteXmp(@TempDirectory.TempDir Path tempDir) throws IOException, Trans * Test, which writes multiple metadata entries to a PDF and reads them again to test the size. */ @Test - void testWriteMultipleBibEntries(@TempDirectory.TempDir Path tempDir) throws IOException, TransformerException { - + void testWriteMultipleBibEntries(@TempDir Path tempDir) throws IOException, TransformerException { Path pdfFile = this.createDefaultFile("JabRef_writeMultiple.pdf", tempDir); List entries = Arrays.asList(olly2018, vapnik2000, toral2006); diff --git a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java index c646bab55bb..6a2ee9bc5e8 100644 --- a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java +++ b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java @@ -20,7 +20,7 @@ class PreferencesMigrationsTest { private final String[] oldStylePatterns = new String[]{"\\bibtexkey", "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}"}; private final String[] newStylePatterns = new String[]{"[bibtexkey]", - "[bibtexkey] - [fulltitle]"}; + "[bibtexkey] - [title]"}; @BeforeEach void setUp() { diff --git a/src/test/java/org/jabref/model/database/BibDatabaseTest.java b/src/test/java/org/jabref/model/database/BibDatabaseTest.java index 8e3f3b89194..d5632433ff1 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseTest.java @@ -122,6 +122,32 @@ public void hasStringLabelFindsString() { assertFalse(database.hasStringLabel("VLSI")); } + @Test + public void addStringAsCollection() { + BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); + List strings = Arrays.asList(string); + database.addStrings(strings); + assertEquals(Optional.of(string), database.getStringByName("DSP")); + } + + @Test + public void addStringAsCollectionWithUpdatedContent() { + BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); + List strings = Arrays.asList(string, new BibtexString("DSP", "ABCD")); + database.addStrings(strings); + assertEquals(Optional.of(string), database.getStringByName("DSP")); + } + + @Test + public void addStringAsCollectionWithNewContent() { + BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); + BibtexString vlsi = new BibtexString("VLSI", "Very Large Scale Integration"); + List strings = Arrays.asList(string, vlsi); + database.addStrings(strings); + assertEquals(Optional.of(string), database.getStringByName("DSP")); + assertEquals(Optional.of(vlsi), database.getStringByName("VLSI")); + } + @Test public void addSameStringLabelTwiceThrowsKeyCollisionException() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); @@ -253,7 +279,7 @@ public void resolveForStringsOddHashMarkAtTheEnd() { @Test public void getUsedStrings() { - BibEntry entry = new BibEntry(new CustomEntryType(IdGenerator.next(),"required","optional")); + BibEntry entry = new BibEntry(new CustomEntryType(IdGenerator.next(), "required", "optional")); entry.setField("author", "#AAA#"); BibtexString tripleA = new BibtexString("AAA", "Some other #BBB#"); BibtexString tripleB = new BibtexString("BBB", "Some more text"); diff --git a/src/test/java/org/jabref/model/entry/BibEntryTests.java b/src/test/java/org/jabref/model/entry/BibEntryTests.java index 872ba189f65..b2e0d35cdaf 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryTests.java +++ b/src/test/java/org/jabref/model/entry/BibEntryTests.java @@ -396,19 +396,6 @@ public void removeKeywordsWithExistingKeywordsRemovesThem() { assertEquals(KeywordList.parse("kw3", ','), keywordEntry.getKeywords(',')); } - @Test - public void testGroupAndSearchHits() { - BibEntry be = new BibEntry(); - be.setGroupHit(true); - assertTrue(be.isGroupHit()); - be.setGroupHit(false); - assertFalse(be.isGroupHit()); - be.setSearchHit(true); - assertTrue(be.isSearchHit()); - be.setSearchHit(false); - assertFalse(be.isSearchHit()); - } - @Test public void setCiteKey() { BibEntry be = new BibEntry(); diff --git a/src/test/java/org/jabref/model/groups/TexGroupTest.java b/src/test/java/org/jabref/model/groups/TexGroupTest.java index 3d869bee22f..e2408b08308 100644 --- a/src/test/java/org/jabref/model/groups/TexGroupTest.java +++ b/src/test/java/org/jabref/model/groups/TexGroupTest.java @@ -6,19 +6,29 @@ import org.jabref.logic.auxparser.DefaultAuxParser; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; +import org.jabref.model.metadata.MetaData; import org.jabref.model.util.DummyFileUpdateMonitor; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class TexGroupTest { + private MetaData metaData; + + @BeforeEach + public void setUp() throws Exception { + metaData = new MetaData(); + } + @Test public void containsReturnsTrueForEntryInAux() throws Exception { Path auxFile = Paths.get(TexGroupTest.class.getResource("paper.aux").toURI()); - TexGroup group = new TexGroup("paper", GroupHierarchyType.INDEPENDENT, auxFile, new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor()); + TexGroup group = new TexGroup("paper", GroupHierarchyType.INDEPENDENT, auxFile, new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor(), metaData); BibEntry inAux = new BibEntry(); inAux.setCiteKey("Darwin1888"); @@ -28,10 +38,20 @@ public void containsReturnsTrueForEntryInAux() throws Exception { @Test public void containsReturnsTrueForEntryNotInAux() throws Exception { Path auxFile = Paths.get(TexGroupTest.class.getResource("paper.aux").toURI()); - TexGroup group = new TexGroup("paper", GroupHierarchyType.INDEPENDENT, auxFile, new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor()); + TexGroup group = new TexGroup("paper", GroupHierarchyType.INDEPENDENT, auxFile, new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor(), metaData); BibEntry notInAux = new BibEntry(); notInAux.setCiteKey("NotInAux2017"); assertFalse(group.contains(notInAux)); } + + @Test + public void getFilePathReturnsRelativePath() throws Exception { + Path auxFile = Paths.get(TexGroupTest.class.getResource("paper.aux").toURI()); + String user = "Darwin"; + metaData.setLaTexFileDirectory(user, auxFile.getParent()); + TexGroup group = new TexGroup("paper", GroupHierarchyType.INDEPENDENT, auxFile, new DefaultAuxParser(new BibDatabase()), new DummyFileUpdateMonitor(), metaData, user); + + assertEquals("paper.aux", group.getFilePath().toString()); + } } diff --git a/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml b/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml index ddb29f48635..8c03b8f17a4 100644 --- a/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml +++ b/src/test/resources/org/jabref/logic/exporter/Docbook5ExportFormat.xml @@ -37,4 +37,4 @@ - \ No newline at end of file + diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest3.bib b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest3.bib index 13eb9b9a606..9bd2b47b290 100644 --- a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest3.bib +++ b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest3.bib @@ -4,7 +4,6 @@ @incollection{ doi = {10.1201/b19107-2}, issn = {978-1-4822-5326-9}, journal = {Dermoscopy Image Analysis}, - month = {#nov#}, number = {0}, pages = {1-22}, publisher = {CRC Press}, diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest6.bib b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest6.bib index e94772ff175..12a03af5704 100644 --- a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest6.bib +++ b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest6.bib @@ -4,7 +4,6 @@ @article{ database = {PMC}, issn = {1537-744X}, journal = {The Scientific World Journal}, - month = {#mar#}, number = {PMC3654245}, pages = {219840}, publisher = {Hindawi Publishing Corporation}, diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest8_date.bib b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest8_date.bib new file mode 100644 index 00000000000..8c200fa3c7a --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest8_date.bib @@ -0,0 +1,15 @@ +@article{, + author = {Valle-Delgado, J. J. and Molina-Bolívar, J. A. and Galisteo-González, F. and Gálvez-Ruiz, M. J. and Feiler, A. and Rutland, M. W.}, + comment = {doi: 10.1063/1.1954747}, + doi = {10.1063/1.1954747}, + issn = {0021-9606}, + journal = {J. Chem. Phys.}, + month = {#jul#}, + number = {3}, + pages = {034708}, + publisher = {American Institute of Physics}, + title = {Hydration forces between silica surfaces: Experimental data and predictions from different theories}, + url = {https://doi.org/10.1063/1.1954747}, + volume = {123}, + year = {2005} +} \ No newline at end of file diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest8_date.ris b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest8_date.ris new file mode 100644 index 00000000000..2ba45d82897 --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest8_date.ris @@ -0,0 +1,30 @@ + + + + + +TY - JOUR +T1 - Hydration forces between silica surfaces: Experimental data and predictions from different theories +AU - Valle-Delgado,J. J. +AU - Molina-Bolívar,J. A. +AU - Galisteo-González,F. +AU - Gálvez-Ruiz,M. J. +AU - Feiler,A. +AU - Rutland,M. W. +Y1 - 2005/07/15 +PY - 2005 +DA - 2005/07/15 +N1 - doi: 10.1063/1.1954747 +DO - 10.1063/1.1954747 +T2 - The Journal of Chemical Physics +JF - The Journal of Chemical Physics +JO - J. Chem. Phys. +SP - 034708 +VL - 123 +IS - 3 +PB - American Institute of Physics +SN - 0021-9606 +M3 - doi: 10.1063/1.1954747 +UR - https://doi.org/10.1063/1.1954747 +Y2 - 2019/03/28 +ER -