From 67ba45f2493cbd34a28bdd942675bf14ebe63752 Mon Sep 17 00:00:00 2001 From: Gennadiy Date: Sat, 18 Apr 2020 11:54:12 +0300 Subject: [PATCH 01/32] Added JabRef logo as tiff for Mac OS installer (retina support) #5759 (#6306) * Updated CHANGELOG.md * Added background_dmg.tiff file --- CHANGELOG.md | 1 + buildres/mac/background_dmg.tiff | Bin 0 -> 63070 bytes 2 files changed, 1 insertion(+) create mode 100644 buildres/mac/background_dmg.tiff diff --git a/CHANGELOG.md b/CHANGELOG.md index ff6295cde77..b1e42eda23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We added tooltips for most fields in the entry editor containing a short description. [#5847](https://github.com/JabRef/jabref/issues/5847) - We added support for basic markdown in custom formatted previews [#6194](https://github.com/JabRef/jabref/issues/6194) - We now show the number of items found and selected to import in the online search dialog. [#6248](https://github.com/JabRef/jabref/pull/6248) +- We created a new install screen for macOS. [#5759](https://github.com/JabRef/jabref/issues/5759) ### Changed diff --git a/buildres/mac/background_dmg.tiff b/buildres/mac/background_dmg.tiff new file mode 100644 index 0000000000000000000000000000000000000000..62782b1a6c3fa388140ba7c8b4aabc6823c4a99f GIT binary patch literal 63070 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 Date: Sat, 18 Apr 2020 11:16:10 +0200 Subject: [PATCH 02/32] Fix JabRef version for Snapcraft build --- snap/snapcraft.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index ef33d746b49..928fd3ca9be 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -48,9 +48,9 @@ environment: parts: jabref: plugin: dump - # source: build/distribution/JabRef-5.0-portable_linux.tar.gz + # source: build/distribution/JabRef-5.1-portable_linux.tar.gz # Use this source for debug purposes: - source: https://builds.jabref.org/master/JabRef-5.0-portable_linux.tar.gz + source: https://builds.jabref.org/master/JabRef-5.1-portable_linux.tar.gz stage-packages: - x11-utils override-build: | From 5816f944513821fbe5883c469b0c5425066ab4e9 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 18 Apr 2020 13:15:06 +0200 Subject: [PATCH 03/32] Remove caching in deployment scripts (#6309) --- .github/workflows/deployment.yml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 03d6b558c2d..271d9f56406 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -54,27 +54,6 @@ jobs: uses: actions/setup-java@v1 with: java-version: 14 - - uses: actions/cache@v1 - name: Restore gradle cache - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-cache-${{ hashFiles('**/*.gradle') }} - # in case there is no cache for the current OS, fall back to any other OS - restore-keys: | - ${{ runner.os }}-gradle-cache- - Linux-gradle-cache-${{ hashFiles('**/*.gradle') }} - Windows-gradle-cache-${{ hashFiles('**/*.gradle') }} - macOS-gradle-cache-${{ hashFiles('**/*.gradle') }} - - uses: actions/cache@v1 - name: Cache gradle wrapper - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - # in case there is no cache for the current OS, fall back to any other OS - restore-keys: | - Linux-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - Windows-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - macOS-gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} - name: Build runtime image run: ./gradlew -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jlinkZip - name: Build installer From c2991ff5588d0ff71c96c2db136052ac22f374f9 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 18 Apr 2020 13:48:21 +0200 Subject: [PATCH 04/32] Add links to all browser extensions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9470e7343bd..5a5c21917e3 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ JabRef supports you in every step of your research work. - Easily retrieve and link full-text articles - Fetch complete bibliographic information based on ISBN, DOI, PubMed-ID and arXiv-ID - Extract metadata from PDFs -- [JabFox Firefox Add-on](https://addons.mozilla.org/en-US/firefox/addon/jabfox/) lets you import new references directly from the browser with one click +- Import new references directly from the browser with one click using the [official browser extension](https://github.com/JabRef/JabRef-Browser-Extension) for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/jabfox?src=external-github), [Chrome](https://chrome.google.com/webstore/detail/jabref-browser-extension/bifehkofibaamoeaopjglfkddgkijdlh), [Edge](https://microsoftedge.microsoft.com/addons/detail/pgkajmkfgbehiomipedjhoddkejohfna) and [Vivaldi](https://chrome.google.com/webstore/detail/jabref-browser-extension/bifehkofibaamoeaopjglfkddgkijdlh) ### Organize From c57ed37c0f63f13e2e884e6dec399fcd60c5b3e6 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 18 Apr 2020 13:50:57 +0200 Subject: [PATCH 05/32] Fix link to Firefox extension --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a5c21917e3..75e1544736f 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ JabRef supports you in every step of your research work. - Easily retrieve and link full-text articles - Fetch complete bibliographic information based on ISBN, DOI, PubMed-ID and arXiv-ID - Extract metadata from PDFs -- Import new references directly from the browser with one click using the [official browser extension](https://github.com/JabRef/JabRef-Browser-Extension) for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/jabfox?src=external-github), [Chrome](https://chrome.google.com/webstore/detail/jabref-browser-extension/bifehkofibaamoeaopjglfkddgkijdlh), [Edge](https://microsoftedge.microsoft.com/addons/detail/pgkajmkfgbehiomipedjhoddkejohfna) and [Vivaldi](https://chrome.google.com/webstore/detail/jabref-browser-extension/bifehkofibaamoeaopjglfkddgkijdlh) +- Import new references directly from the browser with one click using the [official browser extension](https://github.com/JabRef/JabRef-Browser-Extension) for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/jabref/?src=external-github), [Chrome](https://chrome.google.com/webstore/detail/jabref-browser-extension/bifehkofibaamoeaopjglfkddgkijdlh), [Edge](https://microsoftedge.microsoft.com/addons/detail/pgkajmkfgbehiomipedjhoddkejohfna) and [Vivaldi](https://chrome.google.com/webstore/detail/jabref-browser-extension/bifehkofibaamoeaopjglfkddgkijdlh) ### Organize From 2f07d685f4cdb79d877b343df9dfa4dd52e8d747 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sat, 18 Apr 2020 14:07:23 +0200 Subject: [PATCH 06/32] add resource dir for mac --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bef63748c5d..937bf8d5abd 100644 --- a/build.gradle +++ b/build.gradle @@ -678,11 +678,13 @@ jlink { if (OperatingSystem.current().isMacOsX()) { imageOptions = [ '--icon', "${projectDir}/src/main/resources/icons/jabref.icns", + '--resource-dir', "${projectDir}/buildres/mac" ] installerOptions = [ '--vendor', 'JabRef', '--app-version', "${project.version}", - '--file-associations', "${projectDir}/buildres/mac/bibtexAssociations.properties" + '--file-associations', "${projectDir}/buildres/mac/bibtexAssociations.properties", + '--resource-dir', "${projectDir}/buildres/mac" ] } } From 46f18c9200675f876c86dc02294b7e096f08f283 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sat, 18 Apr 2020 14:38:02 +0200 Subject: [PATCH 07/32] rename to jabref-background --- ...ckground_dmg.tiff => JabRef-background_dmg.tiff} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename buildres/mac/{background_dmg.tiff => JabRef-background_dmg.tiff} (100%) diff --git a/buildres/mac/background_dmg.tiff b/buildres/mac/JabRef-background_dmg.tiff similarity index 100% rename from buildres/mac/background_dmg.tiff rename to buildres/mac/JabRef-background_dmg.tiff From 42788b5f5ac3cbaf280b2858c39eda9302532e10 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sat, 18 Apr 2020 16:48:28 +0200 Subject: [PATCH 08/32] add verbose to installer --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 937bf8d5abd..30c24a17b76 100644 --- a/build.gradle +++ b/build.gradle @@ -648,6 +648,7 @@ jlink { installerOptions = [ '--vendor', 'JabRef', '--app-version', "${project.version}", + '--verbose', '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36', '--win-dir-chooser', '--win-shortcut', @@ -662,6 +663,7 @@ jlink { '--icon', "${projectDir}/src/main/resources/icons/JabRef-icon-64.png", ] installerOptions = [ + '--verbose', '--vendor', 'JabRef', '--app-version', "${project.version}", // '--temp', "$buildDir/installer", @@ -681,6 +683,7 @@ jlink { '--resource-dir', "${projectDir}/buildres/mac" ] installerOptions = [ + '--verbose', '--vendor', 'JabRef', '--app-version', "${project.version}", '--file-associations', "${projectDir}/buildres/mac/bibtexAssociations.properties", From 38e3aa7f777ee9ae547a62070d32d2db03b76386 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sat, 18 Apr 2020 20:50:05 +0200 Subject: [PATCH 09/32] rename to correct file and use -i option --- .github/workflows/deployment.yml | 2 +- ...f-background_dmg.tiff => JabRef-background.tiff} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename buildres/mac/{JabRef-background_dmg.tiff => JabRef-background.tiff} (100%) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 271d9f56406..742641675f2 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -57,7 +57,7 @@ jobs: - name: Build runtime image run: ./gradlew -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jlinkZip - name: Build installer - run: ./gradlew -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jpackage + run: ./gradlew -i -PprojVersion="${{ steps.gitversion.outputs.AssemblySemVer }}" -PprojVersionInfo="${{ steps.gitversion.outputs.InformationalVersion }}" jpackage shell: bash - name: Package application image run: ${{ matrix.archivePortable }} diff --git a/buildres/mac/JabRef-background_dmg.tiff b/buildres/mac/JabRef-background.tiff similarity index 100% rename from buildres/mac/JabRef-background_dmg.tiff rename to buildres/mac/JabRef-background.tiff From 2f1c6abc576d0ed0deaff97269f3dc20bbfbc45e Mon Sep 17 00:00:00 2001 From: Christoph Date: Sun, 19 Apr 2020 17:38:19 +0200 Subject: [PATCH 10/32] Update README.md Fixes #6311 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75e1544736f..7f7567724aa 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ We view pull requests as a collaborative process. Submit a pull request early to get feedback from the team on work in progress. We will discuss improvements with you and agree to merge them once the [developers](https://github.com/JabRef/jabref/blob/master/DEVELOPERS) approve. -If you want a step-by-step walk-through on how to set-up your workspace, please check [this guideline](https://devdocs.jabref.org/guidelines-for-setting-up-a-local-workspace/). +If you want a step-by-step walk-through on how to set-up your workspace, please check [this guideline](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace). To compile JabRef from source, you need a Java Development Kit 14 and `JAVA_HOME` pointing to this JDK. To run it, just execute `gradlew run`. From 1c3834f3034b324eef58a90f90eaebc24b92bda7 Mon Sep 17 00:00:00 2001 From: Christoph Date: Sun, 19 Apr 2020 18:52:00 +0200 Subject: [PATCH 11/32] Add JabRef to startmenu on windows (#6312) That's also one thing that bothered me --- CHANGELOG.md | 1 + build.gradle | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e42eda23e..e360078930c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where custom jstyles for Open/LibreOffice where not saved correctly. [#6170](https://github.com/JabRef/jabref/issues/6170) - We fixed an issue where the INSPIRE fetcher was no longer working [#6229](https://github.com/JabRef/jabref/issues/6229) - We fixed the display of icon both in the main table and linked file editor. [#6169](https://github.com/JabRef/jabref/issues/6169) +- We fixed an issue where the windows installer did not create an entry in the start menu [bug report in the forum](https://discourse.jabref.org/t/error-while-fetching-from-doi/2018/3) ### Removed diff --git a/build.gradle b/build.gradle index 30c24a17b76..7ae17914f2d 100644 --- a/build.gradle +++ b/build.gradle @@ -652,6 +652,7 @@ jlink { '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36', '--win-dir-chooser', '--win-shortcut', + '--win-menu', '--temp', "$buildDir/installer", '--resource-dir', "${projectDir}/buildres/windows", '--file-associations', "${projectDir}/buildres/windows/bibtexAssociations.properties" From 5217bade557aa51bf3031f3764adca197beb34bf Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 19 Apr 2020 22:47:09 +0200 Subject: [PATCH 12/32] Remove cache of auto completion results (#6310) --- src/main/java/org/jabref/gui/BasePanel.java | 42 +----- .../AutoCompleteSuggestionProvider.java | 13 -- .../autocompleter/AutoCompleteUpdater.java | 34 ----- .../BibEntrySuggestionProvider.java | 35 +++-- .../ContentSelectorSuggestionProvider.java | 27 +--- .../EmptySuggestionProvider.java | 29 ++++ .../FieldValueSuggestionProvider.java | 17 +-- .../JournalsSuggestionProvider.java | 14 +- .../PersonNameSuggestionProvider.java | 55 ++++--- .../StringSuggestionProvider.java | 24 +-- .../gui/autocompleter/SuggestionProvider.java | 140 +++--------------- .../autocompleter/SuggestionProviders.java | 61 +++----- .../autocompleter/WordSuggestionProvider.java | 29 ++-- .../fieldeditors/AbstractEditorViewModel.java | 8 +- .../gui/fieldeditors/BibtexKeyEditor.java | 4 +- .../BibtexKeyEditorViewModel.java | 4 +- .../jabref/gui/fieldeditors/DateEditor.java | 4 +- .../gui/fieldeditors/DateEditorViewModel.java | 4 +- .../EditorTypeEditorViewModel.java | 4 +- .../jabref/gui/fieldeditors/FieldEditors.java | 10 +- .../fieldeditors/GenderEditorViewModel.java | 4 +- .../gui/fieldeditors/IdentifierEditor.java | 4 +- .../IdentifierEditorViewModel.java | 4 +- .../gui/fieldeditors/JournalEditor.java | 4 +- .../fieldeditors/JournalEditorViewModel.java | 4 +- .../gui/fieldeditors/KeywordsEditor.java | 4 +- .../gui/fieldeditors/LinkedEntriesEditor.java | 8 +- .../LinkedEntriesEditorViewModel.java | 4 +- .../gui/fieldeditors/LinkedFilesEditor.java | 4 +- .../LinkedFilesEditorViewModel.java | 4 +- .../fieldeditors/MapBasedEditorViewModel.java | 4 +- .../fieldeditors/MonthEditorViewModel.java | 4 +- .../fieldeditors/OptionEditorViewModel.java | 4 +- .../jabref/gui/fieldeditors/OwnerEditor.java | 4 +- .../fieldeditors/OwnerEditorViewModel.java | 4 +- .../PaginationEditorViewModel.java | 4 +- .../PatentTypeEditorViewModel.java | 4 +- .../gui/fieldeditors/PersonsEditor.java | 4 +- .../fieldeditors/PersonsEditorViewModel.java | 4 +- .../jabref/gui/fieldeditors/SimpleEditor.java | 6 +- .../fieldeditors/SimpleEditorViewModel.java | 4 +- .../gui/fieldeditors/TypeEditorViewModel.java | 4 +- .../jabref/gui/fieldeditors/UrlEditor.java | 4 +- .../gui/fieldeditors/UrlEditorViewModel.java | 4 +- .../fieldeditors/YesNoEditorViewModel.java | 4 +- .../jabref/gui/search/GlobalSearchBar.java | 10 +- .../BibEntrySuggestionProviderTest.java | 71 +++++---- .../DefaultAutoCompleterTest.java | 93 ++++++------ .../FieldValueSuggestionProviderTest.java | 99 ++++++------- .../PersonNameSuggestionProviderTest.java | 115 +++++++------- .../IdentifierEditorViewModelTest.java | 10 +- 51 files changed, 434 insertions(+), 628 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/autocompleter/AutoCompleteSuggestionProvider.java delete mode 100644 src/main/java/org/jabref/gui/autocompleter/AutoCompleteUpdater.java create mode 100644 src/main/java/org/jabref/gui/autocompleter/EmptySuggestionProvider.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 341686c1aae..69ae14cfdff 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -14,9 +14,7 @@ import javafx.scene.layout.StackPane; import org.jabref.Globals; -import org.jabref.JabRefExecutorService; import org.jabref.gui.autocompleter.AutoCompletePreferences; -import org.jabref.gui.autocompleter.AutoCompleteUpdater; import org.jabref.gui.autocompleter.PersonNameSuggestionProvider; import org.jabref.gui.autocompleter.SuggestionProviders; import org.jabref.gui.collab.DatabaseChangeMonitor; @@ -42,7 +40,6 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.KeyCollisionException; import org.jabref.model.database.event.BibDatabaseContextChangedEvent; -import org.jabref.model.database.event.CoarseChangeFilter; import org.jabref.model.database.event.EntriesAddedEvent; import org.jabref.model.database.event.EntriesRemovedEvent; import org.jabref.model.database.shared.DatabaseLocation; @@ -93,12 +90,10 @@ public class BasePanel extends StackPane { // the query the user searches when this BasePanel is active private Optional currentSearchQuery = Optional.empty(); private Optional changeMonitor = Optional.empty(); - private JabRefExecutorService executorService; public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabaseContext bibDatabaseContext, ExternalFileTypes externalFileTypes) { this.preferences = Objects.requireNonNull(preferences); this.frame = Objects.requireNonNull(frame); - this.executorService = JabRefExecutorService.INSTANCE; this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext); this.externalFileTypes = Objects.requireNonNull(externalFileTypes); this.undoManager = frame.getUndoManager(); @@ -114,6 +109,7 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas annotationCache = new FileAnnotationCache(bibDatabaseContext, Globals.prefs.getFilePreferences()); setupMainPanel(); + setupAutoCompletion(); this.getDatabase().registerListener(new SearchListener()); this.getDatabase().registerListener(new EntriesRemovedListener()); @@ -379,11 +375,6 @@ public void setupMainPanel() { splitPane.getItems().add(mainTable); - // Set up name autocompleter for search: - setupAutoCompletion(); - executorService.execute(this::instantiateSearchAutoCompleter); - this.getDatabase().registerListener(new SearchAutoCompleteListener()); - // 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)) @@ -413,28 +404,18 @@ public void setupMainPanel() { private void setupAutoCompletion() { AutoCompletePreferences autoCompletePreferences = preferences.getAutoCompletePreferences(); if (autoCompletePreferences.shouldAutoComplete()) { - suggestionProviders = new SuggestionProviders(autoCompletePreferences, Globals.journalAbbreviationLoader); - suggestionProviders.indexDatabase(getDatabase()); - // Ensure that the suggestion providers are in sync with entries - CoarseChangeFilter changeFilter = new CoarseChangeFilter(bibDatabaseContext); - changeFilter.registerListener(new AutoCompleteUpdater(suggestionProviders)); + suggestionProviders = new SuggestionProviders(getDatabase(), autoCompletePreferences, Globals.journalAbbreviationLoader); } else { // Create empty suggestion providers if auto completion is deactivated suggestionProviders = new SuggestionProviders(); } + searchAutoCompleter = new PersonNameSuggestionProvider(FieldFactory.getPersonNameFields(), getDatabase()); } public void updateSearchManager() { frame.getGlobalSearchBar().setAutoCompleter(searchAutoCompleter); } - private void instantiateSearchAutoCompleter() { - searchAutoCompleter = new PersonNameSuggestionProvider(FieldFactory.getPersonNameFields()); - for (BibEntry entry : bibDatabaseContext.getDatabase().getEntries()) { - searchAutoCompleter.indexEntry(entry); - } - } - private void adjustSplitter() { if (mode == BasePanelMode.SHOWING_EDITOR) { splitPane.setDividerPositions(preferences.getEntryEditorDividerPosition()); @@ -730,23 +711,6 @@ public void listen(EntriesRemovedEvent entriesRemovedEvent) { } } - /** - * Ensures that the search auto completer is up to date when entries are changed AKA Let the auto completer, if any, - * harvest words from the entry Actual methods for autocomplete indexing must run in javafx thread - */ - private class SearchAutoCompleteListener { - - @Subscribe - public void listen(EntriesAddedEvent addedEntriesEvent) { - DefaultTaskExecutor.runInJavaFXThread(() -> addedEntriesEvent.getBibEntries().forEach(entry -> searchAutoCompleter.indexEntry(entry))); - } - - @Subscribe - public void listen(EntryChangedEvent entryChangedEvent) { - DefaultTaskExecutor.runInJavaFXThread(() -> searchAutoCompleter.indexEntry(entryChangedEvent.getBibEntry())); - } - } - /** * Ensures that the results of the current search are updated when a new entry is inserted into the database Actual * methods for performing search must run in javafx thread diff --git a/src/main/java/org/jabref/gui/autocompleter/AutoCompleteSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/AutoCompleteSuggestionProvider.java deleted file mode 100644 index 1f188238191..00000000000 --- a/src/main/java/org/jabref/gui/autocompleter/AutoCompleteSuggestionProvider.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jabref.gui.autocompleter; - -import java.util.Collection; - -import javafx.util.Callback; - -import org.jabref.model.entry.BibEntry; - -import org.controlsfx.control.textfield.AutoCompletionBinding; - -public interface AutoCompleteSuggestionProvider extends Callback> { - void indexEntry(BibEntry entry); -} diff --git a/src/main/java/org/jabref/gui/autocompleter/AutoCompleteUpdater.java b/src/main/java/org/jabref/gui/autocompleter/AutoCompleteUpdater.java deleted file mode 100644 index 7ace3ef5bba..00000000000 --- a/src/main/java/org/jabref/gui/autocompleter/AutoCompleteUpdater.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.jabref.gui.autocompleter; - -import java.util.List; - -import org.jabref.model.database.event.EntriesAddedEvent; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.event.EntryChangedEvent; - -import com.google.common.eventbus.Subscribe; - -/** - * Ensures that suggestion providers are up to date when entries are changed or added. - */ -public class AutoCompleteUpdater { - - private final SuggestionProviders suggestionProviders; - - public AutoCompleteUpdater(SuggestionProviders suggestionProviders) { - this.suggestionProviders = suggestionProviders; - } - - @Subscribe - public void listen(EntriesAddedEvent entryAddedEvent) { - List entries = entryAddedEvent.getBibEntries(); - for (BibEntry entry : entries) { - suggestionProviders.indexEntry(entry); - } - } - - @Subscribe - public void listen(EntryChangedEvent entryChangedEvent) { - suggestionProviders.indexEntry(entryChangedEvent.getBibEntry()); - } -} diff --git a/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java index 3a5ecbffae4..3cf297c71c1 100644 --- a/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/BibEntrySuggestionProvider.java @@ -1,25 +1,31 @@ package org.jabref.gui.autocompleter; import java.util.Comparator; +import java.util.stream.Stream; import org.jabref.logic.bibtex.comparator.EntryComparator; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.InternalField; +import org.jabref.model.strings.StringUtil; +import com.google.common.base.Equivalence; import org.controlsfx.control.textfield.AutoCompletionBinding; /** * Delivers possible completions as a list of {@link BibEntry} based on their cite key. */ -public class BibEntrySuggestionProvider extends SuggestionProvider implements AutoCompleteSuggestionProvider { +public class BibEntrySuggestionProvider extends SuggestionProvider { - @Override - public void indexEntry(BibEntry entry) { - if (entry == null) { - return; - } + private final BibDatabase database; + + public BibEntrySuggestionProvider(BibDatabase database) { + this.database = database; + } - addPossibleSuggestions(entry); + @Override + protected Equivalence getEquivalence() { + return Equivalence.equals().onResultOf(BibEntry::getCiteKeyOptional); } @Override @@ -28,10 +34,15 @@ protected Comparator getComparator() { } @Override - protected boolean isMatch(BibEntry suggestion, AutoCompletionBinding.ISuggestionRequest request) { - String userTextLower = request.getUserText().toLowerCase(); - return suggestion.getCiteKeyOptional() - .map(key -> key.toLowerCase().contains(userTextLower)) - .orElse(false); + protected boolean isMatch(BibEntry entry, AutoCompletionBinding.ISuggestionRequest request) { + String userText = request.getUserText(); + return entry.getCiteKeyOptional() + .map(key -> StringUtil.containsIgnoreCase(key, userText)) + .orElse(false); + } + + @Override + public Stream getSource() { + return database.getEntries().parallelStream(); } } diff --git a/src/main/java/org/jabref/gui/autocompleter/ContentSelectorSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/ContentSelectorSuggestionProvider.java index 6c969f2713b..dc2299fa685 100644 --- a/src/main/java/org/jabref/gui/autocompleter/ContentSelectorSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/ContentSelectorSuggestionProvider.java @@ -1,22 +1,17 @@ package org.jabref.gui.autocompleter; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; - -import org.jabref.model.entry.BibEntry; - -import org.controlsfx.control.textfield.AutoCompletionBinding; +import java.util.stream.Stream; /** * Enriches a suggestion provider by a given set of content selector values. */ -public class ContentSelectorSuggestionProvider implements AutoCompleteSuggestionProvider { +public class ContentSelectorSuggestionProvider extends StringSuggestionProvider { - private final AutoCompleteSuggestionProvider suggestionProvider; + private final SuggestionProvider suggestionProvider; private final List contentSelectorValues; - public ContentSelectorSuggestionProvider(AutoCompleteSuggestionProvider suggestionProvider, + public ContentSelectorSuggestionProvider(SuggestionProvider suggestionProvider, List contentSelectorValues) { this.suggestionProvider = suggestionProvider; @@ -24,17 +19,7 @@ public ContentSelectorSuggestionProvider(AutoCompleteSuggestionProvider } @Override - public Collection call(AutoCompletionBinding.ISuggestionRequest request) { - List suggestions = new ArrayList<>(); - if (suggestionProvider != null) { - suggestions.addAll(suggestionProvider.call(request)); - } - suggestions.addAll(contentSelectorValues); - return suggestions; - } - - @Override - public void indexEntry(BibEntry entry) { - suggestionProvider.indexEntry(entry); + public Stream getSource() { + return Stream.concat(contentSelectorValues.stream(), suggestionProvider.getSource()); } } diff --git a/src/main/java/org/jabref/gui/autocompleter/EmptySuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/EmptySuggestionProvider.java new file mode 100644 index 00000000000..ab7df191fb5 --- /dev/null +++ b/src/main/java/org/jabref/gui/autocompleter/EmptySuggestionProvider.java @@ -0,0 +1,29 @@ +package org.jabref.gui.autocompleter; + +import java.util.Comparator; +import java.util.stream.Stream; + +import com.google.common.base.Equivalence; +import org.controlsfx.control.textfield.AutoCompletionBinding; + +public class EmptySuggestionProvider extends SuggestionProvider { + @Override + protected Equivalence getEquivalence() { + return Equivalence.equals().onResultOf(value -> value); + } + + @Override + protected Comparator getComparator() { + return Comparator.naturalOrder(); + } + + @Override + protected boolean isMatch(String candidate, AutoCompletionBinding.ISuggestionRequest request) { + return false; + } + + @Override + public Stream getSource() { + return Stream.empty(); + } +} diff --git a/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java index 87048951ec4..1fae672e250 100644 --- a/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/FieldValueSuggestionProvider.java @@ -1,27 +1,26 @@ package org.jabref.gui.autocompleter; import java.util.Objects; +import java.util.stream.Stream; -import org.jabref.model.entry.BibEntry; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.field.Field; /** * Stores the full content of one field. */ -class FieldValueSuggestionProvider extends StringSuggestionProvider implements AutoCompleteSuggestionProvider { +class FieldValueSuggestionProvider extends StringSuggestionProvider { private final Field field; + private final BibDatabase database; - FieldValueSuggestionProvider(Field field) { + FieldValueSuggestionProvider(Field field, BibDatabase database) { this.field = Objects.requireNonNull(field); + this.database = database; } @Override - public void indexEntry(BibEntry entry) { - if (entry == null) { - return; - } - - entry.getField(field).ifPresent(fieldValue -> addPossibleSuggestions(fieldValue.trim())); + public Stream getSource() { + return database.getEntries().parallelStream().flatMap(entry -> entry.getField(field).stream()); } } diff --git a/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java index 5e8b5c95f4d..37e5d872977 100644 --- a/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/JournalsSuggestionProvider.java @@ -1,18 +1,17 @@ package org.jabref.gui.autocompleter; -import java.util.List; -import java.util.stream.Collectors; - -import org.jabref.logic.journals.Abbreviation; import org.jabref.logic.journals.JournalAbbreviationLoader; -import org.jabref.logic.journals.JournalAbbreviationPreferences; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.field.Field; public class JournalsSuggestionProvider extends FieldValueSuggestionProvider { - JournalsSuggestionProvider(Field field, AutoCompletePreferences preferences, + JournalsSuggestionProvider(Field field, BibDatabase database, AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { - super(field); + super(field, database); + + /* + TODO: Reenable JournalAbbreviationPreferences journalAbbreviationPreferences = preferences.getJournalAbbreviationPreferences(); List journals = abbreviationLoader.getRepository(journalAbbreviationPreferences) @@ -20,5 +19,6 @@ public class JournalsSuggestionProvider extends FieldValueSuggestionProvider { .map(Abbreviation::getName) .collect(Collectors.toList()); addPossibleSuggestions(journals); + */ } } diff --git a/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java index db84646648d..2ff7d4a4ed1 100644 --- a/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/PersonNameSuggestionProvider.java @@ -3,59 +3,68 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Map; import java.util.Objects; +import java.util.stream.Stream; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.Author; import org.jabref.model.entry.AuthorList; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; +import org.jabref.model.strings.StringUtil; +import com.google.common.base.Equivalence; import org.controlsfx.control.textfield.AutoCompletionBinding; /** * Delivers possible completions as a list of {@link Author}s. */ -public class PersonNameSuggestionProvider extends SuggestionProvider implements AutoCompleteSuggestionProvider { +public class PersonNameSuggestionProvider extends SuggestionProvider { private final Collection fields; - private final Comparator authorComparator = Comparator.comparing(Author::getNameForAlphabetization); + private final BibDatabase database; - PersonNameSuggestionProvider(Field fieldName) { - this(Collections.singletonList(Objects.requireNonNull(fieldName))); + PersonNameSuggestionProvider(Field field, BibDatabase database) { + this(Collections.singletonList(Objects.requireNonNull(field)), database); } - public PersonNameSuggestionProvider(Collection fields) { + public PersonNameSuggestionProvider(Collection fields, BibDatabase database) { super(); this.fields = Objects.requireNonNull(fields); + this.database = database; + } + public Stream getAuthors(BibEntry entry) { + return entry.getFieldMap() + .entrySet() + .stream() + .filter(fieldValuePair -> fields.contains(fieldValuePair.getKey())) + .map(Map.Entry::getValue) + .map(AuthorList::parse) + .flatMap(authors -> authors.getAuthors().stream()); } @Override - public void indexEntry(BibEntry entry) { - if (entry == null) { - return; - } - - for (Field field : fields) { - entry.getField(field).ifPresent(fieldValue -> { - AuthorList authorList = AuthorList.parse(fieldValue); - for (Author author : authorList.getAuthors()) { - addPossibleSuggestions(author); - } - }); - } + protected Equivalence getEquivalence() { + return Equivalence.equals().onResultOf(Author::getLastOnly); } @Override protected Comparator getComparator() { - return authorComparator; + return Comparator.comparing(Author::getNameForAlphabetization); + } + + @Override + protected boolean isMatch(Author candidate, AutoCompletionBinding.ISuggestionRequest request) { + return StringUtil.containsIgnoreCase(candidate.getLastFirst(false), request.getUserText()); } @Override - protected boolean isMatch(Author suggestion, AutoCompletionBinding.ISuggestionRequest request) { - String userTextLower = request.getUserText().toLowerCase(); - String suggestionStr = suggestion.getLastFirst(false).toLowerCase(); - return suggestionStr.contains(userTextLower); + public Stream getSource() { + return database.getEntries() + .parallelStream() + .flatMap(this::getAuthors); } } diff --git a/src/main/java/org/jabref/gui/autocompleter/StringSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/StringSuggestionProvider.java index 1ec2cf0c97d..01ba19ef39e 100644 --- a/src/main/java/org/jabref/gui/autocompleter/StringSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/StringSuggestionProvider.java @@ -1,26 +1,30 @@ package org.jabref.gui.autocompleter; import java.util.Comparator; +import java.util.stream.Stream; -import org.controlsfx.control.textfield.AutoCompletionBinding; - -class StringSuggestionProvider extends SuggestionProvider { +import org.jabref.model.strings.StringUtil; - private final Comparator stringComparator = Comparator.naturalOrder(); +import com.google.common.base.Equivalence; +import org.controlsfx.control.textfield.AutoCompletionBinding; - public StringSuggestionProvider() { +abstract class StringSuggestionProvider extends SuggestionProvider { + @Override + protected Equivalence getEquivalence() { + return Equivalence.equals().onResultOf(value -> value); } @Override protected Comparator getComparator() { - return stringComparator; + return Comparator.naturalOrder(); } @Override - protected boolean isMatch(String suggestion, AutoCompletionBinding.ISuggestionRequest request) { - String userTextLower = request.getUserText().toLowerCase(); - String suggestionStr = suggestion.toLowerCase(); - return suggestionStr.contains(userTextLower); + protected boolean isMatch(String candidate, AutoCompletionBinding.ISuggestionRequest request) { + return StringUtil.containsIgnoreCase(candidate, request.getUserText()); } + + @Override + public abstract Stream getSource(); } diff --git a/src/main/java/org/jabref/gui/autocompleter/SuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/SuggestionProvider.java index ee18b7d7b26..8d6bba4633a 100644 --- a/src/main/java/org/jabref/gui/autocompleter/SuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/SuggestionProvider.java @@ -26,145 +26,49 @@ */ package org.jabref.gui.autocompleter; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; -import java.util.List; - -import javafx.util.Callback; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import com.google.common.base.Equivalence; import org.controlsfx.control.textfield.AutoCompletionBinding.ISuggestionRequest; /** * This is a simple implementation of a generic suggestion provider callback. - * The complexity of suggestion generation is O(n) where n is the number of possible suggestions. * * @param Type of suggestions - * - * This class is a copy of {@link impl.org.controlsfx.autocompletion.SuggestionProvider} with the only difference that - * we use a set instead of list to store the suggestions in order to eliminate duplicates. */ -public abstract class SuggestionProvider implements Callback> { - - private final Collection possibleSuggestions = new HashSet<>(); - private final Object possibleSuggestionsLock = new Object(); - - /** - * Create a default suggestion provider based on the toString() method of the generic objects - * @param possibleSuggestions All possible suggestions - */ - public static SuggestionProvider create(Collection possibleSuggestions) { - return create(null, possibleSuggestions); - } - - /** - * Create a default suggestion provider based on the toString() method of the generic objects - * using the provided stringConverter - * - * @param stringConverter A stringConverter which converts generic T into a string - * @param possibleSuggestions All possible suggestions - */ - public static SuggestionProvider create(Callback stringConverter, Collection possibleSuggestions) { - SuggestionProviderString suggestionProvider = new SuggestionProviderString<>(stringConverter); - suggestionProvider.addPossibleSuggestions(possibleSuggestions); - return suggestionProvider; - } - - /** - * Add the given new possible suggestions to this SuggestionProvider - */ - public void addPossibleSuggestions(@SuppressWarnings("unchecked") T... newPossible) { - addPossibleSuggestions(Arrays.asList(newPossible)); - } - - /** - * Add the given new possible suggestions to this SuggestionProvider - */ - public void addPossibleSuggestions(Collection newPossible) { - synchronized (possibleSuggestionsLock) { - possibleSuggestions.addAll(newPossible); - } - } - - /** - * Remove all current possible suggestions - */ - public void clearSuggestions() { - synchronized (possibleSuggestionsLock) { - possibleSuggestions.clear(); - } - } +public abstract class SuggestionProvider { - @Override - public final Collection call(final ISuggestionRequest request) { - List suggestions = new ArrayList<>(); + public final Collection provideSuggestions(ISuggestionRequest request) { if (!request.getUserText().isEmpty()) { - synchronized (possibleSuggestionsLock) { - for (T possibleSuggestion : possibleSuggestions) { - if (isMatch(possibleSuggestion, request)) { - suggestions.add(possibleSuggestion); - } - } - } - suggestions.sort(getComparator()); + Comparator comparator = getComparator(); + Equivalence equivalence = getEquivalence(); + return getSource().filter(candidate -> isMatch(candidate, request)) + .map(equivalence::wrap) // Need to do a bit of acrobatic as there is no distinctBy method + .distinct() + .limit(10) + .map(Equivalence.Wrapper::get) + .sorted(comparator) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); } - return suggestions; } + protected abstract Equivalence getEquivalence(); + /** * Get the comparator to order the suggestions */ protected abstract Comparator getComparator(); /** - * Check the given possible suggestion is a match (is a valid suggestion) - */ - protected abstract boolean isMatch(T suggestion, ISuggestionRequest request); - - /** - * This is a simple string based suggestion provider. - * All generic suggestions T are turned into strings for processing. - * + * Check the given candidate is a match (ie a valid suggestion) */ - private static class SuggestionProviderString extends SuggestionProvider { + protected abstract boolean isMatch(T candidate, ISuggestionRequest request); - private Callback stringConverter; - - private final Comparator stringComparator = new Comparator() { - @Override - public int compare(T o1, T o2) { - String o1str = stringConverter.call(o1); - String o2str = stringConverter.call(o2); - return o1str.compareTo(o2str); - } - }; - - /** - * Create a new SuggestionProviderString - */ - public SuggestionProviderString(Callback stringConverter) { - this.stringConverter = stringConverter; - - // In case no stringConverter was provided, use the default strategy - if (this.stringConverter == null) { - this.stringConverter = obj -> obj != null ? obj.toString() : ""; - } - } - - /**{@inheritDoc}*/ - @Override - protected Comparator getComparator() { - return stringComparator; - } - - /**{@inheritDoc}*/ - @Override - protected boolean isMatch(T suggestion, ISuggestionRequest request) { - String userTextLower = request.getUserText().toLowerCase(); - String suggestionStr = suggestion.toString().toLowerCase(); - return suggestionStr.contains(userTextLower); - } - } + public abstract Stream getSource(); } diff --git a/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java b/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java index 4f8f76a405c..b05caec70c8 100644 --- a/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java +++ b/src/main/java/org/jabref/gui/autocompleter/SuggestionProviders.java @@ -1,72 +1,47 @@ package org.jabref.gui.autocompleter; -import java.util.HashMap; -import java.util.Map; import java.util.Objects; import java.util.Set; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldProperty; import org.jabref.model.entry.field.StandardField; public class SuggestionProviders { - /** - * key: field name - */ - private final Map> providers = new HashMap<>(); + private final boolean isEmpty; + private BibDatabase database; + private AutoCompletePreferences preferences; + private JournalAbbreviationLoader abbreviationLoader; - /** - * Empty - */ - public SuggestionProviders() { - - } - - public SuggestionProviders(AutoCompletePreferences preferences, - JournalAbbreviationLoader abbreviationLoader) { - Objects.requireNonNull(preferences); - - Set completeFields = preferences.getCompleteFields(); - for (Field field : completeFields) { - AutoCompleteSuggestionProvider autoCompleter = initalizeSuggestionProvider(field, preferences, abbreviationLoader); - providers.put(field, autoCompleter); - } + public SuggestionProviders(BibDatabase database, AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { + this.database = database; + this.preferences = Objects.requireNonNull(preferences); + this.abbreviationLoader = abbreviationLoader; + this.isEmpty = false; } - public AutoCompleteSuggestionProvider getForField(Field field) { - return providers.get(field); - } - - public void indexDatabase(BibDatabase database) { - for (BibEntry entry : database.getEntries()) { - indexEntry(entry); - } + public SuggestionProviders() { + this.isEmpty = true; } - /** - * This methods assures all information in the given entry is included as suggestions. - */ - public void indexEntry(BibEntry bibEntry) { - for (AutoCompleteSuggestionProvider autoCompleter : providers.values()) { - autoCompleter.indexEntry(bibEntry); + public SuggestionProvider getForField(Field field) { + if (isEmpty) { + return new EmptySuggestionProvider(); } - } - private AutoCompleteSuggestionProvider initalizeSuggestionProvider(Field field, AutoCompletePreferences preferences, JournalAbbreviationLoader abbreviationLoader) { Set fieldProperties = field.getProperties(); if (fieldProperties.contains(FieldProperty.PERSON_NAMES)) { - return new PersonNameSuggestionProvider(field); + return new PersonNameSuggestionProvider(field, database); } else if (fieldProperties.contains(FieldProperty.SINGLE_ENTRY_LINK)) { - return new BibEntrySuggestionProvider(); + return new BibEntrySuggestionProvider(database); } else if (fieldProperties.contains(FieldProperty.JOURNAL_NAME) || StandardField.PUBLISHER.equals(field)) { - return new JournalsSuggestionProvider(field, preferences, abbreviationLoader); + return new JournalsSuggestionProvider(field, database, preferences, abbreviationLoader); } else { - return new WordSuggestionProvider(field); + return new WordSuggestionProvider(field, database); } } } diff --git a/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java b/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java index a591d684a3b..f83d047b0f7 100644 --- a/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java +++ b/src/main/java/org/jabref/gui/autocompleter/WordSuggestionProvider.java @@ -1,35 +1,28 @@ package org.jabref.gui.autocompleter; import java.util.Objects; -import java.util.StringTokenizer; +import java.util.stream.Stream; -import org.jabref.model.entry.BibEntry; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.field.Field; /** - * Stores all words in the given field which are separated by SEPARATING_CHARS. + * Stores all words in the given field. */ -public class WordSuggestionProvider extends StringSuggestionProvider implements AutoCompleteSuggestionProvider { - - private static final String SEPARATING_CHARS = ";,\n "; +public class WordSuggestionProvider extends StringSuggestionProvider { private final Field field; + private final BibDatabase database; - public WordSuggestionProvider(Field field) { + public WordSuggestionProvider(Field field, BibDatabase database) { this.field = Objects.requireNonNull(field); + this.database = database; } @Override - public void indexEntry(BibEntry entry) { - if (entry == null) { - return; - } - - entry.getField(field).ifPresent(fieldValue -> { - StringTokenizer tok = new StringTokenizer(fieldValue, SEPARATING_CHARS); - while (tok.hasMoreTokens()) { - addPossibleSuggestions(tok.nextToken()); - } - }); + public Stream getSource() { + return database.getEntries() + .parallelStream() + .flatMap(entry -> entry.getFieldAsWords(field).stream()); } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java index a699f15f20c..eb21c30ea53 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java @@ -10,7 +10,7 @@ import org.jabref.JabRefGUI; import org.jabref.gui.AbstractViewModel; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.BindingsHelper; import org.jabref.logic.integrity.FieldCheckers; @@ -28,11 +28,11 @@ public class AbstractEditorViewModel extends AbstractViewModel { protected final Field field; protected StringProperty text = new SimpleStringProperty(""); protected BibEntry entry; - private final AutoCompleteSuggestionProvider suggestionProvider; + private final SuggestionProvider suggestionProvider; private final CompositeValidator fieldValidator; private ObjectBinding fieldBinding; - public AbstractEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public AbstractEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { this.field = field; this.suggestionProvider = suggestionProvider; @@ -72,6 +72,6 @@ public void bindToEntry(BibEntry entry) { } public Collection complete(AutoCompletionBinding.ISuggestionRequest request) { - return suggestionProvider.call(request); + return suggestionProvider.provideSuggestions(request); } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditor.java b/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditor.java index 89737ceaa0f..581a927b19a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditor.java @@ -10,7 +10,7 @@ import org.jabref.gui.DialogService; import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.StandardActions; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -26,7 +26,7 @@ public class BibtexKeyEditor extends HBox implements FieldEditorFX { @FXML private Button generateCiteKeyButton; @FXML private EditorTextField textField; - public BibtexKeyEditor(Field field, JabRefPreferences preferences, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, BibDatabaseContext databaseContext, UndoManager undoManager, DialogService dialogService) { + public BibtexKeyEditor(Field field, JabRefPreferences preferences, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, BibDatabaseContext databaseContext, UndoManager undoManager, DialogService dialogService) { this.preferences = preferences; this.viewModel = new BibtexKeyEditorViewModel(field, suggestionProvider, fieldCheckers, preferences.getEntryEditorPreferences(), databaseContext, undoManager, dialogService); diff --git a/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditorViewModel.java index 4da93f60b87..5bf29034fbb 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/BibtexKeyEditorViewModel.java @@ -3,7 +3,7 @@ import javax.swing.undo.UndoManager; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.bibtexkeypattern.GenerateBibtexKeySingleAction; import org.jabref.gui.entryeditor.EntryEditorPreferences; import org.jabref.logic.integrity.FieldCheckers; @@ -18,7 +18,7 @@ public class BibtexKeyEditorViewModel extends AbstractEditorViewModel { private final UndoManager undoManager; private final DialogService dialogService; - public BibtexKeyEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, EntryEditorPreferences preferences, BibDatabaseContext databaseContext, UndoManager undoManager, DialogService dialogService) { + public BibtexKeyEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, EntryEditorPreferences preferences, BibDatabaseContext databaseContext, UndoManager undoManager, DialogService dialogService) { super(field, suggestionProvider, fieldCheckers); this.preferences = preferences; this.databaseContext = databaseContext; diff --git a/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java b/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java index c6d8a8a58e6..cd8ad8785ca 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java @@ -6,7 +6,7 @@ import javafx.scene.Parent; import javafx.scene.layout.HBox; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.util.component.TemporalAccessorPicker; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; @@ -19,7 +19,7 @@ public class DateEditor extends HBox implements FieldEditorFX { @FXML private DateEditorViewModel viewModel; @FXML private TemporalAccessorPicker datePicker; - public DateEditor(Field field, DateTimeFormatter dateFormatter, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public DateEditor(Field field, DateTimeFormatter dateFormatter, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { this.viewModel = new DateEditorViewModel(field, suggestionProvider, dateFormatter, fieldCheckers); ViewLoader.view(this) diff --git a/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java index 7dc8f3735a8..96ffe10c09e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java @@ -6,7 +6,7 @@ import javafx.util.StringConverter; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.Date; import org.jabref.model.entry.field.Field; @@ -15,7 +15,7 @@ public class DateEditorViewModel extends AbstractEditorViewModel { private final DateTimeFormatter dateFormatter; - public DateEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, DateTimeFormatter dateFormatter, FieldCheckers fieldCheckers) { + public DateEditorViewModel(Field field, SuggestionProvider suggestionProvider, DateTimeFormatter dateFormatter, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.dateFormatter = dateFormatter; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java index b11500977b9..1de303d3f8d 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -12,7 +12,7 @@ public class EditorTypeEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(7); - public EditorTypeEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public EditorTypeEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); itemMap.put("editor", Localization.lang("Editor")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index 77c02ef2e2d..b8396cedd42 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -8,8 +8,8 @@ import org.jabref.Globals; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.ContentSelectorSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.autocompleter.SuggestionProviders; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.integrity.FieldCheckers; @@ -43,7 +43,7 @@ public static FieldEditorFX getForField(final Field field, final UndoManager undoManager) { final Set fieldProperties = field.getProperties(); - final AutoCompleteSuggestionProvider suggestionProvider = getSuggestionProvider(field, suggestionProviders, databaseContext.getMetaData()); + final SuggestionProvider suggestionProvider = getSuggestionProvider(field, suggestionProviders, databaseContext.getMetaData()); final FieldCheckers fieldCheckers = new FieldCheckers( databaseContext, @@ -101,14 +101,14 @@ public static FieldEditorFX getForField(final Field field, } @SuppressWarnings("unchecked") - private static AutoCompleteSuggestionProvider getSuggestionProvider(Field field, SuggestionProviders suggestionProviders, MetaData metaData) { - AutoCompleteSuggestionProvider suggestionProvider = suggestionProviders.getForField(field); + private static SuggestionProvider getSuggestionProvider(Field field, SuggestionProviders suggestionProviders, MetaData metaData) { + SuggestionProvider suggestionProvider = suggestionProviders.getForField(field); List contentSelectorValues = metaData.getContentSelectorValuesForField(field); if (!contentSelectorValues.isEmpty()) { // Enrich auto completion by content selector values try { - return new ContentSelectorSuggestionProvider((AutoCompleteSuggestionProvider) suggestionProvider, contentSelectorValues); + return new ContentSelectorSuggestionProvider((SuggestionProvider) suggestionProvider, contentSelectorValues); } catch (ClassCastException exception) { LOGGER.error("Content selectors are only supported for normal fields with string-based auto completion."); return suggestionProvider; diff --git a/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java index 090f49eeba3..0a71d908215 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -12,7 +12,7 @@ public class GenderEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(7); - public GenderEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public GenderEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); itemMap.put("sf", Localization.lang("Female name")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java index 9a3262dee69..cbc572f5216 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java @@ -10,7 +10,7 @@ import javafx.scene.layout.HBox; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.integrity.FieldCheckers; @@ -30,7 +30,7 @@ public class IdentifierEditor extends HBox implements FieldEditorFX { @FXML private Button lookupIdentifierButton; private Optional entry; - public IdentifierEditor(Field field, TaskExecutor taskExecutor, DialogService dialogService, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { + public IdentifierEditor(Field field, TaskExecutor taskExecutor, DialogService dialogService, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { this.viewModel = new IdentifierEditorViewModel(field, suggestionProvider, taskExecutor, dialogService, fieldCheckers); ViewLoader.view(this) diff --git a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java index caf29158122..c35c1a5d9b3 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java @@ -10,7 +10,7 @@ import org.jabref.JabRefGUI; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.mergeentries.FetchAndMergeEntry; import org.jabref.gui.util.BackgroundTask; @@ -33,7 +33,7 @@ public class IdentifierEditorViewModel extends AbstractEditorViewModel { private TaskExecutor taskExecutor; private DialogService dialogService; - public IdentifierEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, TaskExecutor taskExecutor, DialogService dialogService, FieldCheckers fieldCheckers) { + public IdentifierEditorViewModel(Field field, SuggestionProvider suggestionProvider, TaskExecutor taskExecutor, DialogService dialogService, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.taskExecutor = taskExecutor; diff --git a/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java b/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java index f4d46b93262..9c9bc5ee9c8 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java @@ -4,8 +4,8 @@ import javafx.scene.Parent; import javafx.scene.layout.HBox; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.journals.JournalAbbreviationRepository; @@ -20,7 +20,7 @@ public class JournalEditor extends HBox implements FieldEditorFX { @FXML private JournalEditorViewModel viewModel; @FXML private EditorTextField textField; - public JournalEditor(Field field, JournalAbbreviationRepository journalAbbreviationRepository, JabRefPreferences preferences, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public JournalEditor(Field field, JournalAbbreviationRepository journalAbbreviationRepository, JabRefPreferences preferences, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { this.viewModel = new JournalEditorViewModel(field, suggestionProvider, journalAbbreviationRepository, fieldCheckers); ViewLoader.view(this) diff --git a/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java index 4f3f20e94f6..e07401b91e2 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java @@ -2,7 +2,7 @@ import java.util.Optional; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.journals.JournalAbbreviationRepository; import org.jabref.model.entry.field.Field; @@ -11,7 +11,7 @@ public class JournalEditorViewModel extends AbstractEditorViewModel { private final JournalAbbreviationRepository journalAbbreviationRepository; - public JournalEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, JournalAbbreviationRepository journalAbbreviationRepository, FieldCheckers fieldCheckers) { + public JournalEditorViewModel(Field field, SuggestionProvider suggestionProvider, JournalAbbreviationRepository journalAbbreviationRepository, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.journalAbbreviationRepository = journalAbbreviationRepository; diff --git a/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java b/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java index 02b885c80d3..4af7971c052 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java @@ -1,13 +1,13 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.Field; import org.jabref.preferences.JabRefPreferences; public class KeywordsEditor extends SimpleEditor implements FieldEditorFX { - public KeywordsEditor(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { + public KeywordsEditor(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { super(field, suggestionProvider, fieldCheckers, preferences); } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java index f510063ee90..9568cfce925 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java @@ -5,8 +5,8 @@ import javafx.scene.Parent; import javafx.scene.layout.HBox; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.util.component.TagBar; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseContext; @@ -23,12 +23,12 @@ public class LinkedEntriesEditor extends HBox implements FieldEditorFX { @FXML private TagBar linkedEntriesBar; - public LinkedEntriesEditor(Field field, BibDatabaseContext databaseContext, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public LinkedEntriesEditor(Field field, BibDatabaseContext databaseContext, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { this.viewModel = new LinkedEntriesEditorViewModel(field, suggestionProvider, databaseContext, fieldCheckers); ViewLoader.view(this) - .root(this) - .load(); + .root(this) + .load(); linkedEntriesBar.setFieldProperties(field.getProperties()); linkedEntriesBar.setStringConverter(viewModel.getStringConverter()); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java index 19af58758fe..425f87b6034 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java @@ -8,7 +8,7 @@ import javafx.collections.FXCollections; import javafx.util.StringConverter; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.util.BindingsHelper; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseContext; @@ -24,7 +24,7 @@ public class LinkedEntriesEditorViewModel extends AbstractEditorViewModel { private final BibDatabaseContext databaseContext; private final ListProperty linkedEntries; - public LinkedEntriesEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, BibDatabaseContext databaseContext, FieldCheckers fieldCheckers) { + public LinkedEntriesEditorViewModel(Field field, SuggestionProvider suggestionProvider, BibDatabaseContext databaseContext, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.databaseContext = databaseContext; diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 7dbacc13bc8..56b1086303a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -28,7 +28,7 @@ import org.jabref.Globals; import org.jabref.gui.DialogService; import org.jabref.gui.DragAndDropDataFormats; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.copyfiles.CopySingleFileAction; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; @@ -54,7 +54,7 @@ public class LinkedFilesEditor extends HBox implements FieldEditorFX { private final BibDatabaseContext databaseContext; private final UiThreadObservableList decoratedModelList; - public LinkedFilesEditor(Field field, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, + public LinkedFilesEditor(Field field, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { this.viewModel = new LinkedFilesEditorViewModel(field, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers, preferences); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 471af98aa2f..68413ff3019 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -17,7 +17,7 @@ import javafx.collections.ObservableList; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.externalfiles.AutoSetFileLinksUtil; import org.jabref.gui.externalfiletype.CustomExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileType; @@ -51,7 +51,7 @@ public class LinkedFilesEditorViewModel extends AbstractEditorViewModel { private final PreferencesService preferences; private final ExternalFileTypes externalFileTypes = ExternalFileTypes.getInstance(); - public LinkedFilesEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, + public LinkedFilesEditorViewModel(Field field, SuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, diff --git a/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java index 9fce68893e1..8eeae4fe2e4 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java @@ -5,7 +5,7 @@ import javafx.util.StringConverter; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.Field; @@ -20,7 +20,7 @@ public abstract class MapBasedEditorViewModel extends OptionEditorViewModel suggestionProvider, FieldCheckers fieldCheckers) { + public MapBasedEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); } diff --git a/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java index 3132f8e874d..0e13805984a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java @@ -5,7 +5,7 @@ import javafx.util.StringConverter; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.Month; @@ -15,7 +15,7 @@ public class MonthEditorViewModel extends OptionEditorViewModel { private BibDatabaseMode databaseMode; - public MonthEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers) { + public MonthEditorViewModel(Field field, SuggestionProvider suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.databaseMode = databaseMode; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java index b72a90bf1e6..c98d7a0d28c 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java @@ -4,13 +4,13 @@ import javafx.util.StringConverter; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.Field; public abstract class OptionEditorViewModel extends AbstractEditorViewModel { - public OptionEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public OptionEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); } diff --git a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java index 0f3660e6e35..1a40dbb6e08 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java @@ -5,7 +5,7 @@ import javafx.scene.Parent; import javafx.scene.layout.HBox; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -18,7 +18,7 @@ public class OwnerEditor extends HBox implements FieldEditorFX { @FXML private OwnerEditorViewModel viewModel; @FXML private EditorTextArea textArea; - public OwnerEditor(Field field, JabRefPreferences preferences, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public OwnerEditor(Field field, JabRefPreferences preferences, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { this.viewModel = new OwnerEditorViewModel(field, suggestionProvider, preferences, fieldCheckers); ViewLoader.view(this) diff --git a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java index 171188ad71b..2a1f506ec36 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.Field; import org.jabref.preferences.JabRefPreferences; @@ -8,7 +8,7 @@ public class OwnerEditorViewModel extends AbstractEditorViewModel { private final JabRefPreferences preferences; - public OwnerEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, JabRefPreferences preferences, FieldCheckers fieldCheckers) { + public OwnerEditorViewModel(Field field, SuggestionProvider suggestionProvider, JabRefPreferences preferences, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.preferences = preferences; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java index 218c37641c9..991f3d2ac96 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -12,7 +12,7 @@ public class PaginationEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(7); - public PaginationEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public PaginationEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); itemMap.put("page", Localization.lang("Page")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java index d7410aabf19..89b586c253c 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -12,7 +12,7 @@ public class PatentTypeEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(12); - public PatentTypeEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public PatentTypeEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); itemMap.put("patent", Localization.lang("Patent")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java index 5faa0dbb26d..6b3b9dc1680 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java @@ -4,8 +4,8 @@ import javafx.scene.control.TextInputControl; import javafx.scene.layout.HBox; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.gui.util.uithreadaware.UiThreadStringProperty; import org.jabref.logic.integrity.FieldCheckers; @@ -20,7 +20,7 @@ public class PersonsEditor extends HBox implements FieldEditorFX { private final UiThreadStringProperty decoratedStringProperty; public PersonsEditor(final Field field, - final AutoCompleteSuggestionProvider suggestionProvider, + final SuggestionProvider suggestionProvider, final JabRefPreferences preferences, final FieldCheckers fieldCheckers, final boolean isSingleLine) { diff --git a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java index c85197a8aca..e1354a1ac5f 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java @@ -6,9 +6,9 @@ import org.jabref.gui.autocompleter.AppendPersonNamesStrategy; import org.jabref.gui.autocompleter.AutoCompletePreferences; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionStrategy; import org.jabref.gui.autocompleter.PersonNameStringConverter; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.Author; import org.jabref.model.entry.field.Field; @@ -19,7 +19,7 @@ public class PersonsEditorViewModel extends AbstractEditorViewModel { private final AutoCompletePreferences preferences; - public PersonsEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, AutoCompletePreferences preferences, FieldCheckers fieldCheckers) { + public PersonsEditorViewModel(Field field, SuggestionProvider suggestionProvider, AutoCompletePreferences preferences, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.preferences = preferences; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java index a8e2e91a372..10a0882a91e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java @@ -5,9 +5,9 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; import org.jabref.gui.autocompleter.ContentSelectorSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; @@ -20,7 +20,7 @@ public class SimpleEditor extends HBox implements FieldEditorFX { private final TextInputControl textInput; public SimpleEditor(final Field field, - final AutoCompleteSuggestionProvider suggestionProvider, + final SuggestionProvider suggestionProvider, final FieldCheckers fieldCheckers, final JabRefPreferences preferences, final boolean isSingleLine) { @@ -45,7 +45,7 @@ public SimpleEditor(final Field field, } public SimpleEditor(final Field field, - final AutoCompleteSuggestionProvider suggestionProvider, + final SuggestionProvider suggestionProvider, final FieldCheckers fieldCheckers, final JabRefPreferences preferences) { this(field, suggestionProvider, fieldCheckers, preferences, false); diff --git a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java index cc5b9176e4a..52b4f6b2f07 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java @@ -1,14 +1,14 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AppendWordsStrategy; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionStrategy; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.Field; public class SimpleEditorViewModel extends AbstractEditorViewModel { - public SimpleEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public SimpleEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); } diff --git a/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java index 72b16eda2c9..c4f64880e55 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.field.Field; @@ -12,7 +12,7 @@ public class TypeEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(8); - public TypeEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public TypeEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); itemMap.put("mathesis", Localization.lang("Master's thesis")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java b/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java index 270770a2ea1..b4d53a6d6e0 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java @@ -10,7 +10,7 @@ import javafx.scene.layout.HBox; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.logic.formatter.bibtexfields.CleanupUrlFormatter; import org.jabref.logic.formatter.bibtexfields.TrimWhitespaceFormatter; @@ -26,7 +26,7 @@ public class UrlEditor extends HBox implements FieldEditorFX { @FXML private final UrlEditorViewModel viewModel; @FXML private EditorTextArea textArea; - public UrlEditor(Field field, DialogService dialogService, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { + public UrlEditor(Field field, DialogService dialogService, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) { this.viewModel = new UrlEditorViewModel(field, suggestionProvider, dialogService, fieldCheckers); ViewLoader.view(this) diff --git a/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java index be2a3702c34..76f6f465ef0 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java @@ -6,7 +6,7 @@ import javafx.beans.property.SimpleBooleanProperty; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; @@ -19,7 +19,7 @@ public class UrlEditorViewModel extends AbstractEditorViewModel { private DialogService dialogService; private BooleanProperty validUrlIsNotPresent = new SimpleBooleanProperty(true); - public UrlEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, FieldCheckers fieldCheckers) { + public UrlEditorViewModel(Field field, SuggestionProvider suggestionProvider, DialogService dialogService, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); this.dialogService = dialogService; diff --git a/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java index b4d3c81dafc..a1210b1d2eb 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java @@ -1,6 +1,6 @@ package org.jabref.gui.fieldeditors; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.Field; @@ -11,7 +11,7 @@ public class YesNoEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(2); - public YesNoEditorViewModel(Field field, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + public YesNoEditorViewModel(Field field, SuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { super(field, suggestionProvider, fieldCheckers); itemMap.put("yes", "Yes"); diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 341ff97cc92..94a5e0cbc79 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -42,9 +42,9 @@ import org.jabref.gui.StateManager; import org.jabref.gui.autocompleter.AppendPersonNamesStrategy; import org.jabref.gui.autocompleter.AutoCompleteFirstNameMode; -import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; import org.jabref.gui.autocompleter.PersonNameStringConverter; +import org.jabref.gui.autocompleter.SuggestionProvider; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; @@ -276,12 +276,12 @@ private void informUserAboutInvalidSearchQuery() { currentResults.setText(illegalSearch); } - public void setAutoCompleter(AutoCompleteSuggestionProvider searchCompleter) { + public void setAutoCompleter(SuggestionProvider searchCompleter) { if (Globals.prefs.getAutoCompletePreferences().shouldAutoComplete()) { AutoCompletionTextInputBinding autoComplete = AutoCompletionTextInputBinding.autoComplete(searchField, - searchCompleter, - new PersonNameStringConverter(false, false, AutoCompleteFirstNameMode.BOTH), - new AppendPersonNamesStrategy()); + searchCompleter::provideSuggestions, + new PersonNameStringConverter(false, false, AutoCompleteFirstNameMode.BOTH), + new AppendPersonNamesStrategy()); AutoCompletePopup popup = getPopup(autoComplete); popup.setSkin(new SearchPopupSkin<>(popup)); } diff --git a/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java index 099f6cab1af..8843b932c82 100644 --- a/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/BibEntrySuggestionProviderTest.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Collections; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.junit.jupiter.api.BeforeEach; @@ -13,107 +14,101 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class BibEntrySuggestionProviderTest { +class BibEntrySuggestionProviderTest { private BibEntrySuggestionProvider autoCompleter; + private BibDatabase database; @BeforeEach - public void setUp() throws Exception { - autoCompleter = new BibEntrySuggestionProvider(); + void setUp() throws Exception { + database = new BibDatabase(); + autoCompleter = new BibEntrySuggestionProvider(database); } @Test - public void completeWithoutAddingAnythingReturnsNothing() { - Collection result = autoCompleter.call(getRequest(("test"))); + void completeWithoutAddingAnythingReturnsNothing() { + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingNullReturnsNothing() { - autoCompleter.indexEntry(null); - - Collection result = autoCompleter.call(getRequest(("test"))); - assertEquals(Collections.emptyList(), result); - } - - @Test - public void completeAfterAddingEmptyEntryReturnsNothing() { + void completeAfterAddingEmptyEntryReturnsNothing() { BibEntry entry = new BibEntry(); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeKeyReturnsKey() { + void completeKeyReturnsKey() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("testKey"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testKey"))); assertEquals(Collections.singletonList(entry), result); } @Test - public void completeBeginnigOfKeyReturnsKey() { + void completeBeginningOfKeyReturnsKey() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.singletonList(entry), result); } @Test - public void completeLowercaseKeyReturnsKey() { + void completeLowercaseKeyReturnsKey() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("testkey"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testkey"))); assertEquals(Collections.singletonList(entry), result); } @Test - public void completeNullThrowsException() { + void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); + assertThrows(NullPointerException.class, () -> autoCompleter.provideSuggestions(getRequest((null)))); } @Test - public void completeEmptyStringReturnsNothing() { + void completeEmptyStringReturnsNothing() { BibEntry entry = new BibEntry(); entry.setCiteKey("testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest((""))); + Collection result = autoCompleter.provideSuggestions(getRequest((""))); assertEquals(Collections.emptyList(), result); } @Test - public void completeReturnsMultipleResults() { + void completeReturnsMultipleResults() { BibEntry entryOne = new BibEntry(); entryOne.setCiteKey("testKeyOne"); - autoCompleter.indexEntry(entryOne); + database.insertEntry(entryOne); BibEntry entryTwo = new BibEntry(); entryTwo.setCiteKey("testKeyTwo"); - autoCompleter.indexEntry(entryTwo); + database.insertEntry(entryTwo); - Collection result = autoCompleter.call(getRequest(("testKey"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testKey"))); assertEquals(Arrays.asList(entryTwo, entryOne), result); } @Test - public void completeShortKeyReturnsKey() { + void completeShortKeyReturnsKey() { BibEntry entry = new BibEntry(); entry.setCiteKey("key"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("k"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("k"))); assertEquals(Collections.singletonList(entry), result); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java index f99b4de1b85..8d833b199aa 100644 --- a/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/DefaultAutoCompleterTest.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Collections; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -14,142 +15,136 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class DefaultAutoCompleterTest { +class DefaultAutoCompleterTest { private WordSuggestionProvider autoCompleter; - - @Test - public void initAutoCompleterWithNullFieldThrowsException() { - assertThrows(NullPointerException.class, () -> new WordSuggestionProvider(null)); - } + private BibDatabase database; @BeforeEach - public void setUp() throws Exception { - autoCompleter = new WordSuggestionProvider(StandardField.TITLE); + void setUp() throws Exception { + database = new BibDatabase(); + autoCompleter = new WordSuggestionProvider(StandardField.TITLE, database); } @Test - public void completeWithoutAddingAnythingReturnsNothing() { - Collection result = autoCompleter.call(getRequest(("test"))); - assertEquals(Collections.emptyList(), result); + void initAutoCompleterWithNullFieldThrowsException() { + assertThrows(NullPointerException.class, () -> new WordSuggestionProvider(null, database)); } @Test - public void completeAfterAddingNullReturnsNothing() { - autoCompleter.indexEntry(null); - - Collection result = autoCompleter.call(getRequest(("test"))); + void completeWithoutAddingAnythingReturnsNothing() { + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingEmptyEntryReturnsNothing() { + void completeAfterAddingEmptyEntryReturnsNothing() { BibEntry entry = new BibEntry(); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingEntryWithoutFieldReturnsNothing() { + void completeAfterAddingEntryWithoutFieldReturnsNothing() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "testAuthor"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeValueReturnsValue() { + void completeValueReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testValue"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("testValue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testValue"))); assertEquals(Arrays.asList("testValue"), result); } @Test - public void completeBeginningOfValueReturnsValue() { + void completeBeginningOfValueReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testValue"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Arrays.asList("testValue"), result); } @Test - public void completeLowercaseValueReturnsValue() { + void completeLowercaseValueReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testValue"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("testvalue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testvalue"))); assertEquals(Arrays.asList("testValue"), result); } @Test - public void completeNullThrowsException() { + void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); + assertThrows(NullPointerException.class, () -> autoCompleter.provideSuggestions(getRequest((null)))); } @Test - public void completeEmptyStringReturnsNothing() { + void completeEmptyStringReturnsNothing() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest((""))); + Collection result = autoCompleter.provideSuggestions(getRequest((""))); assertEquals(Collections.emptyList(), result); } @Test - public void completeReturnsMultipleResults() { + void completeReturnsMultipleResults() { BibEntry entryOne = new BibEntry(); entryOne.setField(StandardField.TITLE, "testValueOne"); - autoCompleter.indexEntry(entryOne); + database.insertEntry(entryOne); BibEntry entryTwo = new BibEntry(); entryTwo.setField(StandardField.TITLE, "testValueTwo"); - autoCompleter.indexEntry(entryTwo); + database.insertEntry(entryTwo); - Collection result = autoCompleter.call(getRequest(("testValue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testValue"))); assertEquals(Arrays.asList("testValueOne", "testValueTwo"), result); } @Test - public void completeShortStringReturnsValue() { + void completeShortStringReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "val"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("va"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("va"))); assertEquals(Collections.singletonList("val"), result); } @Test - public void completeBeginnigOfSecondWordReturnsWord() { + void completeBeginnigOfSecondWordReturnsWord() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "test value"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("val"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("val"))); assertEquals(Collections.singletonList("value"), result); } @Test - public void completePartOfWordReturnsValue() { + void completePartOfWordReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "test value"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("lue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("lue"))); assertEquals(Collections.singletonList("value"), result); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java index 51ef4e8e988..99d5728fb03 100644 --- a/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/FieldValueSuggestionProviderTest.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Collections; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; @@ -14,152 +15,146 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class FieldValueSuggestionProviderTest { +class FieldValueSuggestionProviderTest { private FieldValueSuggestionProvider autoCompleter; + private BibDatabase database; @BeforeEach - public void setUp() throws Exception { - autoCompleter = new FieldValueSuggestionProvider(StandardField.TITLE); + void setUp() throws Exception { + database = new BibDatabase(); + autoCompleter = new FieldValueSuggestionProvider(StandardField.TITLE, database); } @Test - public void initAutoCompleterWithNullFieldThrowsException() { - assertThrows(NullPointerException.class, () -> new FieldValueSuggestionProvider(null)); + void initAutoCompleterWithNullFieldThrowsException() { + assertThrows(NullPointerException.class, () -> new FieldValueSuggestionProvider(null, new BibDatabase())); } @Test - public void completeWithoutAddingAnythingReturnsNothing() { - Collection result = autoCompleter.call(getRequest(("test"))); + void completeWithoutAddingAnythingReturnsNothing() { + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingNullReturnsNothing() { - autoCompleter.indexEntry(null); - - Collection result = autoCompleter.call(getRequest(("test"))); - assertEquals(Collections.emptyList(), result); - } - - @Test - public void completeAfterAddingEmptyEntryReturnsNothing() { + void completeAfterAddingEmptyEntryReturnsNothing() { BibEntry entry = new BibEntry(); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingEntryWithoutFieldReturnsNothing() { + void completeAfterAddingEntryWithoutFieldReturnsNothing() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "testAuthor"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeValueReturnsValue() { + void completeValueReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testValue"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("testValue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testValue"))); assertEquals(Arrays.asList("testValue"), result); } @Test - public void completeBeginnigOfValueReturnsValue() { + void completeBeginnigOfValueReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testValue"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Arrays.asList("testValue"), result); } @Test - public void completeLowercaseValueReturnsValue() { + void completeLowercaseValueReturnsValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testValue"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("testvalue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testvalue"))); assertEquals(Arrays.asList("testValue"), result); } @Test - public void completeNullThrowsException() { + void completeNullThrowsException() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest(null))); + assertThrows(NullPointerException.class, () -> autoCompleter.provideSuggestions(getRequest(null))); } @Test - public void completeEmptyStringReturnsNothing() { + void completeEmptyStringReturnsNothing() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testKey"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest((""))); + Collection result = autoCompleter.provideSuggestions(getRequest((""))); assertEquals(Collections.emptyList(), result); } @Test - public void completeReturnsMultipleResults() { + void completeReturnsMultipleResults() { BibEntry entryOne = new BibEntry(); entryOne.setField(StandardField.TITLE, "testValueOne"); - autoCompleter.indexEntry(entryOne); + database.insertEntry(entryOne); BibEntry entryTwo = new BibEntry(); entryTwo.setField(StandardField.TITLE, "testValueTwo"); - autoCompleter.indexEntry(entryTwo); + database.insertEntry(entryTwo); - Collection result = autoCompleter.call(getRequest(("testValue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("testValue"))); assertEquals(Arrays.asList("testValueOne", "testValueTwo"), result); } @Test - public void completeShortStringReturnsFieldValue() { + void completeShortStringReturnsFieldValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "val"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("va"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("va"))); assertEquals(Collections.singletonList("val"), result); } @Test - public void completeBeginnigOfSecondWordReturnsWholeFieldValue() { + void completeBeginnigOfSecondWordReturnsWholeFieldValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "test value"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("val"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("val"))); assertEquals(Collections.singletonList("test value"), result); } @Test - public void completePartOfWordReturnsWholeFieldValue() { + void completePartOfWordReturnsWholeFieldValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "test value"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("lue"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("lue"))); assertEquals(Collections.singletonList("test value"), result); } @Test - public void completeReturnsWholeFieldValue() { + void completeReturnsWholeFieldValue() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "test value"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("te"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("te"))); assertEquals(Collections.singletonList("test value"), result); } } diff --git a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java index ccc681febdd..1c3f344f5da 100644 --- a/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java +++ b/src/test/java/org/jabref/gui/autocompleter/PersonNameSuggestionProviderTest.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Collections; +import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.Author; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; @@ -16,174 +17,168 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class PersonNameSuggestionProviderTest { +class PersonNameSuggestionProviderTest { private final Author vassilisKostakos = new Author("Vassilis", "V.", "", "Kostakos", ""); private PersonNameSuggestionProvider autoCompleter; private BibEntry entry; - - @Test - public void initAutoCompleterWithNullFieldThrowsException() { - assertThrows(NullPointerException.class, () -> new PersonNameSuggestionProvider((Field) null)); - } + private BibDatabase database; @BeforeEach - public void setUp() throws Exception { - autoCompleter = new PersonNameSuggestionProvider(StandardField.AUTHOR); + void setUp() throws Exception { + database = new BibDatabase(); + autoCompleter = new PersonNameSuggestionProvider(StandardField.AUTHOR, database); entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Vassilis Kostakos"); } @Test - public void completeWithoutAddingAnythingReturnsNothing() { - Collection result = autoCompleter.call(getRequest(("test"))); - assertEquals(Collections.emptyList(), result); + void initAutoCompleterWithNullFieldThrowsException() { + assertThrows(NullPointerException.class, () -> new PersonNameSuggestionProvider((Field) null, new BibDatabase())); } @Test - public void completeAfterAddingNullReturnsNothing() { - autoCompleter.indexEntry(null); - - Collection result = autoCompleter.call(getRequest(("test"))); + void completeWithoutAddingAnythingReturnsNothing() { + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingEmptyEntryReturnsNothing() { + void completeAfterAddingEmptyEntryReturnsNothing() { BibEntry entry = new BibEntry(); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeAfterAddingEntryWithoutFieldReturnsNothing() { + void completeAfterAddingEntryWithoutFieldReturnsNothing() { BibEntry entry = new BibEntry(); entry.setField(StandardField.TITLE, "testTitle"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("test"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("test"))); assertEquals(Collections.emptyList(), result); } @Test - public void completeNameReturnsName() { - autoCompleter.indexEntry(entry); + void completeNameReturnsName() { + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("Kostakos"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Kostakos"))); assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test - public void completeBeginningOfNameReturnsName() { - autoCompleter.indexEntry(entry); + void completeBeginningOfNameReturnsName() { + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("Kosta"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Kosta"))); assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test - public void completeLowercaseBeginningOfNameReturnsName() { - autoCompleter.indexEntry(entry); + void completeLowercaseBeginningOfNameReturnsName() { + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("kosta"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("kosta"))); assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test - public void completeNullThrowsException() { - assertThrows(NullPointerException.class, () -> autoCompleter.call(getRequest((null)))); + void completeNullThrowsException() { + assertThrows(NullPointerException.class, () -> autoCompleter.provideSuggestions(getRequest((null)))); } @Test - public void completeEmptyStringReturnsNothing() { - autoCompleter.indexEntry(entry); + void completeEmptyStringReturnsNothing() { + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest((""))); + Collection result = autoCompleter.provideSuggestions(getRequest((""))); assertEquals(Collections.emptyList(), result); } @Test - public void completeReturnsMultipleResults() { - autoCompleter.indexEntry(entry); + void completeReturnsMultipleResults() { + database.insertEntry(entry); BibEntry entryTwo = new BibEntry(); entryTwo.setField(StandardField.AUTHOR, "Kosta"); - autoCompleter.indexEntry(entryTwo); + database.insertEntry(entryTwo); Author authorTwo = new Author("", "", "", "Kosta", ""); - Collection result = autoCompleter.call(getRequest(("Ko"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Ko"))); assertEquals(Arrays.asList(authorTwo, vassilisKostakos), result); } @Test - public void completePartOfNameReturnsName() { - autoCompleter.indexEntry(entry); + void completePartOfNameReturnsName() { + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("osta"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("osta"))); assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test - public void completeBeginningOfFirstNameReturnsName() { - autoCompleter.indexEntry(entry); + void completeBeginningOfFirstNameReturnsName() { + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("Vas"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Vas"))); assertEquals(Collections.singletonList(vassilisKostakos), result); } @Test - public void completeBeginningOfFirstNameReturnsNameWithJr() { + void completeBeginningOfFirstNameReturnsNameWithJr() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Reagle, Jr., Joseph M."); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); Author author = new Author("Joseph M.", "J. M.", "", "Reagle", "Jr."); - Collection result = autoCompleter.call(getRequest(("Jos"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Jos"))); assertEquals(Collections.singletonList(author), result); } @Test - public void completeBeginningOfFirstNameReturnsNameWithVon() { + void completeBeginningOfFirstNameReturnsNameWithVon() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Eric von Hippel"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); Author author = new Author("Eric", "E.", "von", "Hippel", ""); - Collection result = autoCompleter.call(getRequest(("Eric"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Eric"))); assertEquals(Collections.singletonList(author), result); } @Test - public void completeBeginningOfLastNameReturnsNameWithUmlauts() { + void completeBeginningOfLastNameReturnsNameWithUmlauts() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Honig Bär"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); Author author = new Author("Honig", "H.", "", "Bär", ""); - Collection result = autoCompleter.call(getRequest(("Bä"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Bä"))); assertEquals(Collections.singletonList(author), result); } @Test - public void completeVonReturnsName() { + void completeVonReturnsName() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Eric von Hippel"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); Author author = new Author("Eric", "E.", "von", "Hippel", ""); - Collection result = autoCompleter.call(getRequest(("von"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("von"))); assertEquals(Collections.singletonList(author), result); } @Test - public void completeBeginningOfFullNameReturnsName() { + void completeBeginningOfFullNameReturnsName() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Vassilis Kostakos"); - autoCompleter.indexEntry(entry); + database.insertEntry(entry); - Collection result = autoCompleter.call(getRequest(("Kostakos, Va"))); + Collection result = autoCompleter.provideSuggestions(getRequest(("Kostakos, Va"))); assertEquals(Collections.singletonList(vassilisKostakos), result); } } diff --git a/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java index 4f5c437e800..d9bc547941c 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java @@ -1,7 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.DialogService; -import org.jabref.gui.autocompleter.WordSuggestionProvider; +import org.jabref.gui.autocompleter.EmptySuggestionProvider; import org.jabref.gui.util.CurrentThreadTaskExecutor; import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.field.StandardField; @@ -12,17 +12,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -public class IdentifierEditorViewModelTest { +class IdentifierEditorViewModelTest { private IdentifierEditorViewModel viewModel; @BeforeEach - public void setUp() throws Exception { - viewModel = new IdentifierEditorViewModel(StandardField.DOI, new WordSuggestionProvider(StandardField.DOI), new CurrentThreadTaskExecutor(), mock(DialogService.class), mock(FieldCheckers.class)); + void setUp() throws Exception { + viewModel = new IdentifierEditorViewModel(StandardField.DOI, new EmptySuggestionProvider(), new CurrentThreadTaskExecutor(), mock(DialogService.class), mock(FieldCheckers.class)); } @Test - public void validIdentifierIsNotPresentIsTrueForEmptyText() throws Exception { + void validIdentifierIsNotPresentIsTrueForEmptyText() throws Exception { assertTrue(viewModel.validIdentifierIsNotPresentProperty().get()); } } From 5ed32e1c21337e216f773129f22946f61c49fd8a Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Sun, 19 Apr 2020 22:51:29 +0200 Subject: [PATCH 13/32] Fixed missing paste command (#6313) * Fixed missing paste command * CHANGELOG.md --- CHANGELOG.md | 1 + src/main/java/org/jabref/gui/edit/EditAction.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e360078930c..0305cf32c0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where custom jstyles for Open/LibreOffice where not saved correctly. [#6170](https://github.com/JabRef/jabref/issues/6170) - We fixed an issue where the INSPIRE fetcher was no longer working [#6229](https://github.com/JabRef/jabref/issues/6229) - We fixed the display of icon both in the main table and linked file editor. [#6169](https://github.com/JabRef/jabref/issues/6169) +- We fixed the paste entry command in the menu and toolbar, that did not do anything. [#6293](https://github.com/JabRef/jabref/issues/6293) - We fixed an issue where the windows installer did not create an entry in the start menu [bug report in the forum](https://discourse.jabref.org/t/error-while-fetching-from-doi/2018/3) ### Removed diff --git a/src/main/java/org/jabref/gui/edit/EditAction.java b/src/main/java/org/jabref/gui/edit/EditAction.java index e48add2b08c..36794f64ab7 100644 --- a/src/main/java/org/jabref/gui/edit/EditAction.java +++ b/src/main/java/org/jabref/gui/edit/EditAction.java @@ -62,7 +62,7 @@ public void execute() { frame.getCurrentBasePanel().cut(); break; case PASTE: - // handled by FX in TextInputControl#paste + frame.getCurrentBasePanel().paste(); break; case DELETE_ENTRY: frame.getCurrentBasePanel().delete(false); From bc57d22f2a4ae8912d263608cf0a606fbbecd43a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 20 Apr 2020 08:24:58 +0200 Subject: [PATCH 14/32] Improve performance massively by fixing a stupid binding mistake (#6316) --- .../gui/maintable/BibEntryTableViewModel.java | 97 +++++++++++++++---- .../org/jabref/gui/maintable/FieldColumn.java | 54 ++--------- .../gui/maintable/MainTableColumnFactory.java | 6 +- .../gui/maintable/MainTableDataModel.java | 2 +- 4 files changed, 91 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java b/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java index 9397f26de16..8ef28292285 100644 --- a/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java +++ b/src/main/java/org/jabref/gui/maintable/BibEntryTableViewModel.java @@ -12,6 +12,7 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; +import org.jabref.Globals; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; @@ -19,27 +20,54 @@ import org.jabref.model.entry.FileFieldParser; import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldProperty; import org.jabref.model.entry.field.InternalField; +import org.jabref.model.entry.field.OrFields; import org.jabref.model.entry.field.SpecialField; import org.jabref.model.entry.field.StandardField; import org.jabref.model.groups.AbstractGroup; import org.jabref.model.groups.GroupTreeNode; import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.monadic.MonadicBinding; public class BibEntryTableViewModel { private final BibEntry entry; + private final BibDatabase database; + private final MainTableNameFormatter nameFormatter; + private final Map> fieldValues = new HashMap<>(); + private final Map>> specialFieldValues = new HashMap<>(); + private final MonadicBinding> linkedFiles; + private final ObjectBinding> linkedIdentifiers; + private final ObservableValue> matchedGroups; - public BibEntryTableViewModel(BibEntry entry) { + public BibEntryTableViewModel(BibEntry entry, BibDatabaseContext database) { this.entry = entry; + this.database = database.getDatabase(); + this.nameFormatter = new MainTableNameFormatter(Globals.prefs); + + this.linkedFiles = EasyBind.map(getField(StandardField.FILE), FileFieldParser::parse); + this.linkedIdentifiers = createLinkedIdentifiersBinding(entry); + this.matchedGroups = createMatchedGroupsBinding(database); } - public BibEntry getEntry() { - return entry; + private ObjectBinding> createLinkedIdentifiersBinding(BibEntry entry) { + return Bindings.createObjectBinding(() -> { + Map identifiers = new HashMap<>(); + entry.getField(StandardField.URL).ifPresent(value -> identifiers.put(StandardField.URL, value)); + entry.getField(StandardField.DOI).ifPresent(value -> identifiers.put(StandardField.DOI, value)); + entry.getField(StandardField.URI).ifPresent(value -> identifiers.put(StandardField.URI, value)); + entry.getField(StandardField.EPRINT).ifPresent(value -> identifiers.put(StandardField.EPRINT, value)); + return identifiers; + }, + getEntry().getFieldBinding(StandardField.URL), + getEntry().getFieldBinding(StandardField.DOI), + getEntry().getFieldBinding(StandardField.URI), + getEntry().getFieldBinding(StandardField.EPRINT)); } - public Optional getResolvedFieldOrAlias(Field field, BibDatabase database) { - return entry.getResolvedFieldOrAliasLatexFree(field, database); + public BibEntry getEntry() { + return entry; } public ObjectBinding getField(Field field) { @@ -47,29 +75,29 @@ public ObjectBinding getField(Field field) { } public ObservableValue> getSpecialField(SpecialField field) { - return EasyBind.map(getField(field), value -> field.parseValue(value).map(SpecialFieldValueViewModel::new)); + ObservableValue> value = specialFieldValues.get(field); + if (value != null) { + return value; + } else { + value = EasyBind.map(getField(field), fieldValue -> field.parseValue(fieldValue).map(SpecialFieldValueViewModel::new)); + specialFieldValues.put(field, value); + return value; + } } public ObservableValue> getLinkedFiles() { - return EasyBind.map(getField(StandardField.FILE), FileFieldParser::parse); + return linkedFiles; } public ObservableValue> getLinkedIdentifiers() { - return Bindings.createObjectBinding(() -> { - Map linkedIdentifiers = new HashMap<>(); - entry.getField(StandardField.URL).ifPresent(value -> linkedIdentifiers.put(StandardField.URL, value)); - entry.getField(StandardField.DOI).ifPresent(value -> linkedIdentifiers.put(StandardField.DOI, value)); - entry.getField(StandardField.URI).ifPresent(value -> linkedIdentifiers.put(StandardField.URI, value)); - entry.getField(StandardField.EPRINT).ifPresent(value -> linkedIdentifiers.put(StandardField.EPRINT, value)); - return linkedIdentifiers; - }, - getEntry().getFieldBinding(StandardField.URL), - getEntry().getFieldBinding(StandardField.DOI), - getEntry().getFieldBinding(StandardField.URI), - getEntry().getFieldBinding(StandardField.EPRINT)); + return linkedIdentifiers; + } + + public ObservableValue> getMatchedGroups() { + return matchedGroups; } - public ObservableValue> getMatchedGroups(BibDatabaseContext database) { + private ObservableValue> createMatchedGroupsBinding(BibDatabaseContext database) { Optional root = database.getMetaData().getGroups(); if (root.isPresent()) { return EasyBind.map(entry.getFieldBinding(InternalField.GROUPS), field -> { @@ -83,4 +111,33 @@ public ObservableValue> getMatchedGroups(BibDatabaseContext } return new SimpleObjectProperty<>(Collections.emptyList()); } + + public ObservableValue getFields(OrFields fields) { + ObservableValue value = fieldValues.get(fields); + if (value != null) { + return value; + } else { + value = Bindings.createStringBinding(() -> { + boolean isName = false; + + Optional content = Optional.empty(); + for (Field field : fields) { + content = entry.getResolvedFieldOrAlias(field, database); + if (content.isPresent()) { + isName = field.getProperties().contains(FieldProperty.PERSON_NAMES); + break; + } + } + + String result = content.orElse(null); + if (isName) { + return nameFormatter.formatName(result); + } else { + return result; + } + }, entry.getObservables()); + fieldValues.put(fields, value); + return value; + } + } } diff --git a/src/main/java/org/jabref/gui/maintable/FieldColumn.java b/src/main/java/org/jabref/gui/maintable/FieldColumn.java index cc221fcf722..fac40ce2d87 100644 --- a/src/main/java/org/jabref/gui/maintable/FieldColumn.java +++ b/src/main/java/org/jabref/gui/maintable/FieldColumn.java @@ -1,15 +1,7 @@ package org.jabref.gui.maintable; -import java.util.Optional; - -import javafx.beans.binding.Bindings; -import javafx.beans.binding.ObjectBinding; import javafx.beans.value.ObservableValue; -import org.jabref.Globals; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.field.Field; -import org.jabref.model.entry.field.FieldProperty; import org.jabref.model.entry.field.OrFields; /** @@ -17,20 +9,14 @@ */ public class FieldColumn extends MainTableColumn { - private final OrFields bibtexFields; - - private final Optional database; - - private final MainTableNameFormatter nameFormatter; + private final OrFields fields; - public FieldColumn(MainTableColumnModel model, OrFields bibtexFields, BibDatabase database) { + public FieldColumn(MainTableColumnModel model, OrFields fields) { super(model); - this.bibtexFields = bibtexFields; - this.database = Optional.of(database); - this.nameFormatter = new MainTableNameFormatter(Globals.prefs); + this.fields = fields; setText(getDisplayName()); - setCellValueFactory(param -> getColumnValue(param.getValue())); + setCellValueFactory(param -> getFieldValue(param.getValue())); } /** @@ -39,35 +25,15 @@ public FieldColumn(MainTableColumnModel model, OrFields bibtexFields, BibDatabas * @return name to be displayed. null if field is empty. */ @Override - public String getDisplayName() { return bibtexFields.getDisplayName(); } - - private ObservableValue getColumnValue(BibEntryTableViewModel entry) { - if (bibtexFields.isEmpty()) { - return null; - } - - ObjectBinding[] dependencies = bibtexFields.stream().map(entry::getField).toArray(ObjectBinding[]::new); - return Bindings.createStringBinding(() -> computeText(entry), dependencies); + public String getDisplayName() { + return fields.getDisplayName(); } - private String computeText(BibEntryTableViewModel entry) { - boolean isNameColumn = false; - - Optional content = Optional.empty(); - for (Field field : bibtexFields) { - content = entry.getResolvedFieldOrAlias(field, database.orElse(null)); - if (content.isPresent()) { - isNameColumn = field.getProperties().contains(FieldProperty.PERSON_NAMES); - break; - } - } - - String result = content.orElse(null); - - if (isNameColumn) { - return nameFormatter.formatName(result); + private ObservableValue getFieldValue(BibEntryTableViewModel entry) { + if (fields.isEmpty()) { + return null; } else { - return result; + return entry.getFields(fields); } } } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java index a821e343d01..2327da419a2 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableColumnFactory.java @@ -160,7 +160,7 @@ private TableColumn createIndexColumn(MainTableC column.getStyleClass().add(STYLE_ICON_COLUMN); setExactWidth(column, ColumnPreferences.ICON_COLUMN_WIDTH); column.setResizable(false); - column.setCellValueFactory(cellData -> cellData.getValue().getMatchedGroups(database)); + column.setCellValueFactory(cellData -> cellData.getValue().getMatchedGroups()); new ValueTableCellFactory>() .withGraphic(this::createGroupColorRegion) .install(column); @@ -207,8 +207,8 @@ private Node createGroupColorRegion(BibEntryTableViewModel entry, List createFieldColumn(MainTableColumnModel columnModel) { FieldColumn column = new FieldColumn(columnModel, - FieldFactory.parseOrFields(columnModel.getQualifier()), - database.getDatabase()); + FieldFactory.parseOrFields(columnModel.getQualifier()) + ); new ValueTableCellFactory() .withText(text -> text) .install(column); diff --git a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java index 192dd715f4f..c0ee007455b 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java @@ -27,7 +27,7 @@ public class MainTableDataModel { public MainTableDataModel(BibDatabaseContext context) { ObservableList allEntries = BindingsHelper.forUI(context.getDatabase().getEntries()); - ObservableList entriesViewModel = BindingsHelper.mapBacked(allEntries, BibEntryTableViewModel::new); + ObservableList entriesViewModel = BindingsHelper.mapBacked(allEntries, entry -> new BibEntryTableViewModel(entry, context)); entriesFiltered = new FilteredList<>(entriesViewModel); entriesFiltered.predicateProperty().bind( From 56e38b82ff1f44544570a100693b4e6c3f4b50c4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 11:50:47 +0200 Subject: [PATCH 15/32] Bump org.beryx.jlink from 2.17.5 to 2.17.7 (#6324) Bumps org.beryx.jlink from 2.17.5 to 2.17.7. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7ae17914f2d..3bf4556355d 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ plugins { id 'com.github.ben-manes.versions' version '0.28.0' id 'org.javamodularity.moduleplugin' version '1.5.0' id 'org.openjfx.javafxplugin' version '0.0.8' - id 'org.beryx.jlink' version '2.17.5' + id 'org.beryx.jlink' version '2.17.7' // nicer test outputs during running and completion id 'com.adarshr.test-logger' version '2.0.0' From 5c700c39fa19b96952d5384889483198b4ca794f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 11:50:59 +0200 Subject: [PATCH 16/32] Bump flexmark-ext-gfm-tasklist from 0.61.6 to 0.61.16 (#6327) Bumps [flexmark-ext-gfm-tasklist](https://github.com/vsch/flexmark-java) from 0.61.6 to 0.61.16. - [Release notes](https://github.com/vsch/flexmark-java/releases) - [Commits](https://github.com/vsch/flexmark-java/compare/0.61.6...0.61.16) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3bf4556355d..8001ab31a24 100644 --- a/build.gradle +++ b/build.gradle @@ -198,7 +198,7 @@ dependencies { implementation 'com.vladsch.flexmark:flexmark:0.61.6' implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.61.6' - implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.61.6' + implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.61.16' testImplementation 'io.github.classgraph:classgraph:4.8.69' testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' From 4f8819e6ba8ecd5566869b37802e4c7a584591a4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 11:51:38 +0200 Subject: [PATCH 17/32] Bump guava from 28.2-jre to 29.0-jre (#6323) Bumps [guava](https://github.com/google/guava) from 28.2-jre to 29.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8001ab31a24..e4722ae596b 100644 --- a/build.gradle +++ b/build.gradle @@ -151,7 +151,7 @@ dependencies { exclude module: 'oraclepki' } - implementation ('com.google.guava:guava:28.2-jre') { + implementation ('com.google.guava:guava:29.0-jre') { // TODO: Remove this as soon as https://github.com/google/guava/issues/2960 is fixed exclude module: "jsr305" } From 138a677cec6be3d5c0fc7c84ef1b94d94835cf28 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 12:00:07 +0200 Subject: [PATCH 18/32] Bump richtextfx from 0.10.4 to 0.10.5 (#6319) Bumps [richtextfx](https://github.com/FXMisc/RichTextFX) from 0.10.4 to 0.10.5. - [Release notes](https://github.com/FXMisc/RichTextFX/releases) - [Changelog](https://github.com/FXMisc/RichTextFX/blob/master/CHANGELOG.md) - [Commits](https://github.com/FXMisc/RichTextFX/compare/v0.10.4...v0.10.5) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e4722ae596b..b621503f2cd 100644 --- a/build.gradle +++ b/build.gradle @@ -165,7 +165,7 @@ dependencies { implementation 'de.saxsys:mvvmfx:1.8.0' implementation 'org.fxmisc.easybind:easybind:1.0.3' implementation 'org.fxmisc.flowless:flowless:0.6.1' - implementation 'org.fxmisc.richtext:richtextfx:0.10.4' + implementation 'org.fxmisc.richtext:richtextfx:0.10.5' implementation group: 'org.glassfish.hk2.external', name: 'jakarta.inject', version: '2.6.1' implementation 'com.jfoenix:jfoenix:9.0.9' implementation 'org.controlsfx:controlsfx:11.0.1' From 84c68acab801b4c298442edf396a041d6dc24abc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 12:00:56 +0200 Subject: [PATCH 19/32] Bump flexmark from 0.61.6 to 0.61.16 (#6318) Bumps [flexmark](https://github.com/vsch/flexmark-java) from 0.61.6 to 0.61.16. - [Release notes](https://github.com/vsch/flexmark-java/releases) - [Commits](https://github.com/vsch/flexmark-java/compare/0.61.6...0.61.16) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b621503f2cd..e06a78845c7 100644 --- a/build.gradle +++ b/build.gradle @@ -196,7 +196,7 @@ dependencies { exclude module: "log4j-core" } - implementation 'com.vladsch.flexmark:flexmark:0.61.6' + implementation 'com.vladsch.flexmark:flexmark:0.61.16' implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.61.6' implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.61.16' From b3d4a5aa8fadf72ecc5f8508b211872e8b575cd3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 12:01:12 +0200 Subject: [PATCH 20/32] Bump classgraph from 4.8.69 to 4.8.71 (#6322) Bumps [classgraph](https://github.com/classgraph/classgraph) from 4.8.69 to 4.8.71. - [Release notes](https://github.com/classgraph/classgraph/releases) - [Commits](https://github.com/classgraph/classgraph/compare/classgraph-4.8.69...classgraph-4.8.71) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e06a78845c7..576c59a4cea 100644 --- a/build.gradle +++ b/build.gradle @@ -200,7 +200,7 @@ dependencies { implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.61.6' implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.61.16' - testImplementation 'io.github.classgraph:classgraph:4.8.69' + testImplementation 'io.github.classgraph:classgraph:4.8.71' testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.6.2' testImplementation 'org.junit.platform:junit-platform-launcher:1.6.2' From d9fe981eb156f52c9fab77af631aa39a5765b90c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 12:33:01 +0200 Subject: [PATCH 21/32] Bump ridl from 6.3.2 to 6.4.3 (#6326) Bumps ridl from 6.3.2 to 6.4.3. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 576c59a4cea..e014a77ab54 100644 --- a/build.gradle +++ b/build.gradle @@ -130,7 +130,7 @@ dependencies { // DO NOT CHANGE THE libreoffice PREFIX libreoffice 'org.libreoffice:juh:6.3.2' libreoffice 'org.libreoffice:jurt:6.3.2' - libreoffice 'org.libreoffice:ridl:6.3.2' + libreoffice 'org.libreoffice:ridl:6.4.3' libreoffice 'org.libreoffice:unoil:6.3.2' implementation 'io.github.java-diff-utils:java-diff-utils:4.5' From 45fe8b13f2cc61401cb5ff2a9102ff85f5f2afa9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 13:06:42 +0200 Subject: [PATCH 22/32] Bump unoil from 6.3.2 to 6.4.3 (#6320) Bumps unoil from 6.3.2 to 6.4.3. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e014a77ab54..797493b8506 100644 --- a/build.gradle +++ b/build.gradle @@ -131,7 +131,7 @@ dependencies { libreoffice 'org.libreoffice:juh:6.3.2' libreoffice 'org.libreoffice:jurt:6.3.2' libreoffice 'org.libreoffice:ridl:6.4.3' - libreoffice 'org.libreoffice:unoil:6.3.2' + libreoffice 'org.libreoffice:unoil:6.4.3' implementation 'io.github.java-diff-utils:java-diff-utils:4.5' implementation 'info.debatty:java-string-similarity:1.2.1' From 58ef8bc27b78c60eabdd0105a26bdd5e3169c708 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2020 13:06:53 +0200 Subject: [PATCH 23/32] Bump jurt from 6.3.2 to 6.4.3 (#6325) Bumps jurt from 6.3.2 to 6.4.3. Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Christoph --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 797493b8506..501ed8f6743 100644 --- a/build.gradle +++ b/build.gradle @@ -128,8 +128,8 @@ dependencies { // See https://bugs.documentfoundation.org/show_bug.cgi?id=117331#c8 for background information // Use the task bundleLibreOffice to update the bundled jar // DO NOT CHANGE THE libreoffice PREFIX - libreoffice 'org.libreoffice:juh:6.3.2' - libreoffice 'org.libreoffice:jurt:6.3.2' + libreoffice 'org.libreoffice:juh:6.4.3' + libreoffice 'org.libreoffice:jurt:6.4.3' libreoffice 'org.libreoffice:ridl:6.4.3' libreoffice 'org.libreoffice:unoil:6.4.3' From dc1e339c8005c0b6dbb911cf0790cdce6d1dfe75 Mon Sep 17 00:00:00 2001 From: Hussain Arif Date: Tue, 21 Apr 2020 11:55:45 +0500 Subject: [PATCH 24/32] 'Name' textfield on focus instead of 'OK' button when user clicks on 'Add subgroup' option (#6330) * Name field now in focus whenever 'add subgroup' button selected * Updated: Focuson Name Area instead of 'OK' button whenever user presses 'Add subgroup' * Focus on name text area whenever user clicks on Add Subgroup * Focus on name text area when OK button is pressed * Fixed changelog.md Co-authored-by: Hussain Arif --- CHANGELOG.md | 1 + src/main/java/org/jabref/gui/groups/GroupDialogView.java | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0305cf32c0c..7d363c184f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -246,6 +246,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We added a 'LaTeX citations' tab to the entry editor, to search for citations to the active entry in the LaTeX file directory. It can be disabled in the preferences dialog. - We added an option in preferences to allow for integers in field "edition" when running database in bibtex mode. [#4680](https://github.com/JabRef/jabref/issues/4680) - We added the ability to use negation in export filter layouts. [#5138](https://github.com/JabRef/jabref/pull/5138) +- Focus on Name Area instead of 'OK' button whenever user presses 'Add subgroup'. [#6307](https://github.com/JabRef/jabref/issues/6307) ### Fixed diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogView.java b/src/main/java/org/jabref/gui/groups/GroupDialogView.java index 9d11fc25bb4..d6523a97c45 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogView.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogView.java @@ -142,6 +142,7 @@ public void initialize() { validationVisualizer.initVisualization(viewModel.keywordRegexValidationStatus(), keywordGroupSearchTerm); validationVisualizer.initVisualization(viewModel.keywordSearchTermEmptyValidationStatus(), keywordGroupSearchTerm); validationVisualizer.initVisualization(viewModel.keywordFieldEmptyValidationStatus(), keywordGroupSearchField); + nameField.requestFocus(); }); // Binding to the button throws a NPE, since it doesn't exist yet. Working around. From 17a97fdfb7a453095cf4ed90e2c76ff8b3afdea2 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 22 Apr 2020 08:20:04 +0200 Subject: [PATCH 25/32] Add ADR von JUnit vs. AssertJ (#6335) --- docs/adr/0009-use-plain-junit5-for-testing.md | 83 +++++++++++++++++++ .../MainArchitectureTestsWithArchUnit.java | 5 ++ 2 files changed, 88 insertions(+) create mode 100644 docs/adr/0009-use-plain-junit5-for-testing.md diff --git a/docs/adr/0009-use-plain-junit5-for-testing.md b/docs/adr/0009-use-plain-junit5-for-testing.md new file mode 100644 index 00000000000..35d58bf1097 --- /dev/null +++ b/docs/adr/0009-use-plain-junit5-for-testing.md @@ -0,0 +1,83 @@ +# Use Plain JUnit5 for advanced test assertions + +## Context and Problem Statement + +How to write readable test assertions? +How to write readable test assertions for advanced tests? + +## Considered Options + +* Plain JUnit5 +* Hamcrest +* AssertJ + +## Decision Outcome + +Chosen option: "Plain JUnit5", because comes out best \(see below\). + +### Positive Consequences + +* Tests are more readable +* More easy to write tests +* More readable assertions + +### Negative Consequences + +* More complicated testing leads to more complicated assertions + +## Pros and Cons of the Options + +### Plain JUnit5 + +Homepage: +JabRef testing guidelines: + +Example: + +```java +String actual = markdownFormatter.format(source); +assertTrue(actual.contains("Markup
")); +assertTrue(actual.contains("
  • list item one
  • ")); +assertTrue(actual.contains("
  • list item 2
  • ")); +assertTrue(actual.contains("> rest")); +assertFalse(actual.contains("\n")); +``` + +* Good, because Junit5 is "common Java knowledge" +* Bad, because complex assertions tend to get hard to read +* Bad, because no fluent API + +### Hamcrest + +Homepage: + +* Good, because offers advanced matchers (such as `contains`) +* Bad, because not full fluent API +* Bad, because entry barrier is increased + +### AssertJ + +Homepage: + +Example: + +```java +assertThat(markdownFormatter.format(source)) + .contains("Markup
    ") + .contains("
  • list item one
  • ") + .contains("
  • list item 2
  • ") + .contains("> rest") + .doesNotContain("\n"); +``` + +* Good, because offers fluent assertions +* Good, because allows partial string testing to focus on important parts +* Good, because assertions are more readable +* Bad, because not commonly used +* Bad, because newcomers have to learn an additional language to express test cases +* Bad, because entry barrier is increased +* Bad, because expressions of test cases vary from unit test to unit test + +## Links + +* German comparison between Hamcrest and AssertJ: diff --git a/src/test/java/org/jabref/architecture/MainArchitectureTestsWithArchUnit.java b/src/test/java/org/jabref/architecture/MainArchitectureTestsWithArchUnit.java index 6237103e62e..a21e086e326 100644 --- a/src/test/java/org/jabref/architecture/MainArchitectureTestsWithArchUnit.java +++ b/src/test/java/org/jabref/architecture/MainArchitectureTestsWithArchUnit.java @@ -47,6 +47,11 @@ public static void doNotUseGlyphsDirectly(JavaClasses classes) { noClasses().that().resideOutsideOfPackage("org.jabref.gui.icon").should().accessClassesThat().resideInAnyPackage("de.jensd.fx.glyphs", "de.jensd.fx.glyphs.materialdesignicons").check(classes); } + @ArchTest + public static void doNotUseAssertJ(JavaClasses classes) { + noClasses().should().accessClassesThat().resideInAPackage("org.assertj..").check(classes); + } + // "Currently disabled as there is no alternative for the rest of classes who need awt" @ArchIgnore @ArchTest From c7d77670154c1b09d8115013c8f3b4175906219e Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 22 Apr 2020 14:30:40 +0200 Subject: [PATCH 26/32] Improve performance for loading files (#6332) * Improve performance for loading files - Performance improvements around groups - Remove detection of duplicate ID when inserting entries (it's not really possible to create two entries with the same except if you use `setId` manually) - Remove detection of duplicate bibtex keys when opening a file (the result was not used and we have a integrity check for it) - Use EnumMap instead of HashMap to cache fields as keywords (which is only used for Keyword and Groups fields anyway) - Fix bug where latex code was displayed in the maintable - Lazy init of source tab * Fix tests compilation * Include feedback --- .idea/runConfigurations/JabRef_Main.xml | 1 + src/main/java/org/jabref/gui/BasePanel.java | 5 - .../org/jabref/gui/entryeditor/SourceTab.java | 24 +++-- .../jabref/gui/fieldeditors/FieldEditors.java | 2 +- .../gui/fieldeditors/FieldNameLabel.java | 12 +-- .../gui/maintable/BibEntryTableViewModel.java | 10 +- .../gui/maintable/MainTableDataModel.java | 3 +- .../preferences/TableColumnsTabViewModel.java | 10 +- .../jabref/logic/importer/ParserResult.java | 32 +----- .../logic/importer/fetcher/DBLPFetcher.java | 3 +- .../importer/fileformat/BibtexParser.java | 16 +-- .../importer/fileformat/MedlineImporter.java | 3 +- .../fileformat/MedlinePlainImporter.java | 3 +- .../org/jabref/logic/util/UpdateField.java | 8 +- .../jabref/model/database/BibDatabase.java | 33 +++---- .../jabref/model/database/BibDatabases.java | 20 ---- .../java/org/jabref/model/entry/BibEntry.java | 52 +++++----- .../model/entry/field/FieldFactory.java | 2 +- .../model/entry/field/InternalField.java | 5 +- .../model/entry/field/SpecialField.java | 16 +-- .../model/entry/field/StandardField.java | 9 +- .../model/groups/AutomaticKeywordGroup.java | 20 ++-- .../jabref/model/groups/ExplicitGroup.java | 8 +- .../jabref/model/groups/WordKeywordGroup.java | 97 +++++++++++++------ .../model/search/matchers/OrMatcher.java | 4 +- .../java/org/jabref/model/util/ListUtil.java | 33 +++++++ .../org/jabref/model/util/MultiKeyMap.java | 9 +- .../jabref/preferences/JabRefPreferences.java | 2 +- .../gui/UpdateTimestampListenerTest.java | 6 +- .../gui/groups/GroupNodeViewModelTest.java | 25 +++-- .../gui/groups/GroupTreeViewModelTest.java | 13 ++- .../importer/fetcher/MedlineFetcherTest.java | 9 +- .../importer/fileformat/BibtexParserTest.java | 20 +--- .../jabref/logic/layout/LayoutEntryTest.java | 5 +- .../jabref/logic/xmp/XmpUtilWriterTest.java | 9 +- .../ConvertLegacyExplicitGroupsTest.java | 16 +-- .../BibDatabaseModeDetectionTest.java | 26 ++--- .../model/database/BibDatabaseTest.java | 4 +- .../model/groups/ExplicitGroupTest.java | 60 ++++++------ 39 files changed, 309 insertions(+), 326 deletions(-) create mode 100644 src/main/java/org/jabref/model/util/ListUtil.java diff --git a/.idea/runConfigurations/JabRef_Main.xml b/.idea/runConfigurations/JabRef_Main.xml index 4a1ef684c65..d57c0fd5ac5 100644 --- a/.idea/runConfigurations/JabRef_Main.xml +++ b/.idea/runConfigurations/JabRef_Main.xml @@ -2,6 +2,7 @@