From 2862c6d90be6762b862aa6718351cac5a8bbad80 Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Sun, 22 Oct 2023 17:40:54 +1100 Subject: [PATCH 01/11] Add command line skeleton for jump to entry key option --- src/main/java/org/jabref/cli/ArgumentProcessor.java | 8 ++++++++ src/main/java/org/jabref/cli/JabRefCLI.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index 1f436070319..aee673bfb4b 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -277,6 +277,10 @@ public void processArguments() { doAuxImport(loaded); } + if (!cli.isBlank() && cli.isJumpToEntryKey()) { + jumpToEntryKey(); + } + this.parserResults = loaded; } @@ -773,6 +777,10 @@ private Optional fetch(String fetchCommand) { } } + private void jumpToEntryKey(){ + + } + public boolean isBlank() { return cli.isBlank(); } diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index 484201b63ff..40df68edb6d 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -169,6 +169,10 @@ public String getWriteMetadatatoPdf() { cl.hasOption("embeddBibfileInPdf") ? cl.getOptionValue("embeddBibfileInPdf") : null; } + public boolean isJumpToEntryKey() { + return cl.hasOption("jumpToEntryKey"); + } + private static Options getOptions() { Options options = new Options(); @@ -288,6 +292,14 @@ private static Options getOptions() { .argName("CITEKEY1[,CITEKEY2][,CITEKEYn] | PDF1[,PDF2][,PDFn] | all") .build()); + options.addOption(Option + .builder("j") + .longOpt("jumpToEntryKey") + .desc(String.format("%s: '%s'", Localization.lang("Jump to the BibEntry of the given key."), "-j key")) + .hasArg() + .argName("ENTRYKEY") + .build()); + return options; } From ec850525c328d06cc2910b724b1958acf43e21f5 Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Tue, 24 Oct 2023 16:21:03 +1100 Subject: [PATCH 02/11] Add basic logic linking new command line option with gui --- .../org/jabref/cli/ArgumentProcessor.java | 14 ++++++++++--- src/main/java/org/jabref/cli/JabRefCLI.java | 4 ++++ src/main/java/org/jabref/gui/JabRefGUI.java | 20 ++++++++++++++++++- .../jabref/logic/importer/ParserResult.java | 9 +++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index aee673bfb4b..2d22b888a2e 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -278,7 +278,7 @@ public void processArguments() { } if (!cli.isBlank() && cli.isJumpToEntryKey()) { - jumpToEntryKey(); + jumpToEntryKey(loaded, cli.getJumpToEntryKey()); } this.parserResults = loaded; @@ -777,8 +777,16 @@ private Optional fetch(String fetchCommand) { } } - private void jumpToEntryKey(){ - + private void jumpToEntryKey(List loaded, String citationKey) { + // search for this key in imported files + for (ParserResult parserResult : loaded) { + Optional entry = parserResult.getDatabase().getEntryByCitationKey(citationKey); + if (entry.isPresent()) { + parserResult.setEntryToFocus(entry.get()); + return; + } + } + LOGGER.error("Could not find given citation key to jump to"); } public boolean isBlank() { diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index 40df68edb6d..f6b3a2ecdbb 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -169,6 +169,10 @@ public String getWriteMetadatatoPdf() { cl.hasOption("embeddBibfileInPdf") ? cl.getOptionValue("embeddBibfileInPdf") : null; } + public String getJumpToEntryKey() { + return cl.getOptionValue("jumpToEntryKey"); + } + public boolean isJumpToEntryKey() { return cl.hasOption("jumpToEntryKey"); } diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java index 9a402703619..6359f1d01e9 100644 --- a/src/main/java/org/jabref/gui/JabRefGUI.java +++ b/src/main/java/org/jabref/gui/JabRefGUI.java @@ -25,6 +25,7 @@ import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; import org.jabref.logic.shared.exception.NotASharedDatabaseException; import org.jabref.logic.util.WebViewStore; +import org.jabref.model.entry.BibEntry; import org.jabref.model.strings.StringUtil; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.GuiPreferences; @@ -201,12 +202,25 @@ private void openDatabases() { .orElse(preferencesService.getGuiPreferences() .getLastFocusedFile()) .toAbsolutePath(); + // check whether there is a jump to entry and need to focus different file + boolean focusDifferent = false; + Optional focusedEntry = Optional.empty(); + for (ParserResult parserResult : parserResults) { + // Make sure this parser result is its own library instead of imported entries + if (parserResult.getEntryToFocus().isPresent() && !parserResult.toOpenTab()) { + focusDifferent = true; + focusedEntry = parserResult.getEntryToFocus(); + } + } // Add all bibDatabases databases to the frame: boolean first = false; for (ParserResult parserResult : parserResults) { // Define focused tab - if (parserResult.getPath().filter(path -> path.toAbsolutePath().equals(focusedFile)).isPresent()) { + if (parserResult.getPath().filter(path -> path.toAbsolutePath().equals(focusedFile)).isPresent() && !focusDifferent) { + first = true; + } + if (parserResult.getEntryToFocus().isPresent() && focusDifferent) { first = true; } @@ -279,6 +293,10 @@ private void openDatabases() { OpenDatabaseAction.performPostOpenActions(libraryTab, pr); } + // focus a particular entry if CLI has received a jump to entry key command + if (focusedEntry.isPresent()) { + mainFrame.getCurrentLibraryTab().clearAndSelect(focusedEntry.get()); + } LOGGER.debug("Finished adding panels"); } diff --git a/src/main/java/org/jabref/logic/importer/ParserResult.java b/src/main/java/org/jabref/logic/importer/ParserResult.java index 2f134224562..a700696ebb9 100644 --- a/src/main/java/org/jabref/logic/importer/ParserResult.java +++ b/src/main/java/org/jabref/logic/importer/ParserResult.java @@ -26,6 +26,7 @@ public class ParserResult { private boolean invalid; private boolean toOpenTab; private boolean changedOnMigration = false; + private BibEntry entryToFocus; public ParserResult() { this(Collections.emptyList()); @@ -99,6 +100,14 @@ public void setPath(Path path) { file = path; } + public Optional getEntryToFocus() { + return Optional.ofNullable(entryToFocus); + } + + public void setEntryToFocus(BibEntry bibEntry) { + entryToFocus = bibEntry; + } + /** * Add a parser warning. * From 1c14b13c4c372b166db78c46efb74f5dc6987a09 Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Tue, 24 Oct 2023 18:51:52 +1100 Subject: [PATCH 03/11] Remove small bug that opens the wrong library with multiple entries --- src/main/java/org/jabref/gui/JabRefGUI.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java index 6359f1d01e9..7045df74dae 100644 --- a/src/main/java/org/jabref/gui/JabRefGUI.java +++ b/src/main/java/org/jabref/gui/JabRefGUI.java @@ -206,10 +206,11 @@ private void openDatabases() { boolean focusDifferent = false; Optional focusedEntry = Optional.empty(); for (ParserResult parserResult : parserResults) { - // Make sure this parser result is its own library instead of imported entries + // Make sure this parser result is its own library instead of imported BibTex entries if (parserResult.getEntryToFocus().isPresent() && !parserResult.toOpenTab()) { focusDifferent = true; focusedEntry = parserResult.getEntryToFocus(); + break; } } @@ -222,6 +223,7 @@ private void openDatabases() { } if (parserResult.getEntryToFocus().isPresent() && focusDifferent) { first = true; + focusDifferent = false; } if (parserResult.getDatabase().isShared()) { @@ -296,6 +298,7 @@ private void openDatabases() { // focus a particular entry if CLI has received a jump to entry key command if (focusedEntry.isPresent()) { mainFrame.getCurrentLibraryTab().clearAndSelect(focusedEntry.get()); + mainFrame.showLibraryTab(mainFrame.getCurrentLibraryTab()); } LOGGER.debug("Finished adding panels"); From 69563fcf59b5f1ead143303a0c15a9961b215f00 Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Wed, 25 Oct 2023 18:26:01 +1100 Subject: [PATCH 04/11] Add small feedback changes --- src/main/java/org/jabref/cli/ArgumentProcessor.java | 3 +-- src/main/java/org/jabref/cli/JabRefCLI.java | 6 +++--- src/main/java/org/jabref/gui/JabRefGUI.java | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index 2d22b888a2e..53bf71869a9 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -778,7 +778,6 @@ private Optional fetch(String fetchCommand) { } private void jumpToEntryKey(List loaded, String citationKey) { - // search for this key in imported files for (ParserResult parserResult : loaded) { Optional entry = parserResult.getDatabase().getEntryByCitationKey(citationKey); if (entry.isPresent()) { @@ -786,7 +785,7 @@ private void jumpToEntryKey(List loaded, String citationKey) { return; } } - LOGGER.error("Could not find given citation key to jump to"); + System.out.printf("Could not find citation key %s in any library%n", citationKey); } public boolean isBlank() { diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index f6b3a2ecdbb..22b422356be 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -298,10 +298,10 @@ private static Options getOptions() { options.addOption(Option .builder("j") - .longOpt("jumpToEntryKey") - .desc(String.format("%s: '%s'", Localization.lang("Jump to the BibEntry of the given key."), "-j key")) + .longOpt("jumpToKey") + .desc(String.format("%s: '%s'", Localization.lang("Jump to the entry of the given citation key."), "-j key")) .hasArg() - .argName("ENTRYKEY") + .argName("CITEKEY") .build()); return options; diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java index 7045df74dae..a4ee050527e 100644 --- a/src/main/java/org/jabref/gui/JabRefGUI.java +++ b/src/main/java/org/jabref/gui/JabRefGUI.java @@ -206,7 +206,7 @@ private void openDatabases() { boolean focusDifferent = false; Optional focusedEntry = Optional.empty(); for (ParserResult parserResult : parserResults) { - // Make sure this parser result is its own library instead of imported BibTex entries + // Make sure this parser result is its own library instead of imported BibTeX entries if (parserResult.getEntryToFocus().isPresent() && !parserResult.toOpenTab()) { focusDifferent = true; focusedEntry = parserResult.getEntryToFocus(); From c7b62dccdc1462859362160a0592d3dc6ac7f5af Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Wed, 25 Oct 2023 20:43:54 +1100 Subject: [PATCH 05/11] Fixed cli by renaming all method to jumpToEntry --- src/main/java/org/jabref/cli/ArgumentProcessor.java | 6 +++--- src/main/java/org/jabref/cli/JabRefCLI.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index 53bf71869a9..580cd5870df 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -277,8 +277,8 @@ public void processArguments() { doAuxImport(loaded); } - if (!cli.isBlank() && cli.isJumpToEntryKey()) { - jumpToEntryKey(loaded, cli.getJumpToEntryKey()); + if (!cli.isBlank() && cli.isJumpToKey()) { + jumpToKey(loaded, cli.getJumpToKey()); } this.parserResults = loaded; @@ -777,7 +777,7 @@ private Optional fetch(String fetchCommand) { } } - private void jumpToEntryKey(List loaded, String citationKey) { + private void jumpToKey(List loaded, String citationKey) { for (ParserResult parserResult : loaded) { Optional entry = parserResult.getDatabase().getEntryByCitationKey(citationKey); if (entry.isPresent()) { diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index 22b422356be..040405b9cc2 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -169,12 +169,12 @@ public String getWriteMetadatatoPdf() { cl.hasOption("embeddBibfileInPdf") ? cl.getOptionValue("embeddBibfileInPdf") : null; } - public String getJumpToEntryKey() { - return cl.getOptionValue("jumpToEntryKey"); + public String getJumpToKey() { + return cl.getOptionValue("jumpToKey"); } - public boolean isJumpToEntryKey() { - return cl.hasOption("jumpToEntryKey"); + public boolean isJumpToKey() { + return cl.hasOption("jumpToKey"); } private static Options getOptions() { From 7b8c1f563cf44d1a52c7abbad25b89a1e9995221 Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Wed, 25 Oct 2023 21:32:35 +1100 Subject: [PATCH 06/11] Fixed bug that focused libraries of recently opened files over command line arguments --- src/main/java/org/jabref/gui/LibraryTab.java | 2 +- .../org/jabref/gui/importer/actions/OpenDatabaseAction.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/LibraryTab.java b/src/main/java/org/jabref/gui/LibraryTab.java index fc4880d2562..4e5184bcd71 100644 --- a/src/main/java/org/jabref/gui/LibraryTab.java +++ b/src/main/java/org/jabref/gui/LibraryTab.java @@ -222,7 +222,7 @@ public Node createLoadingAnimationLayout() { public void onDatabaseLoadingStarted() { Node loadingLayout = createLoadingAnimationLayout(); getMainTable().placeholderProperty().setValue(loadingLayout); - frame.addTab(this, true); + frame.addTab(this, false); } public void onDatabaseLoadingSucceed(ParserResult result) { diff --git a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java index 4e2854ba764..5eeb451d3cb 100644 --- a/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java @@ -172,9 +172,10 @@ public void openFiles(List filesToOpen) { openTheFile(theFile); fileHistory.newFile(theFile); }); - } else if (toRaise != null) { + } else if (toRaise != null && frame.getCurrentLibraryTab() == null) { // If no files are remaining to open, this could mean that a file was // already open. If so, we may have to raise the correct tab: + // If there is already a library focused, do not show this library frame.showLibraryTab(toRaise); } } From e6a6a9e343840cc38db2deb21097f2ad8b40045e Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Thu, 26 Oct 2023 14:35:39 +1100 Subject: [PATCH 07/11] Add CHANGELOG.md entry and localization entries --- CHANGELOG.md | 1 + src/main/resources/l10n/JabRef_en.properties | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 627167f4fc0..7cd1b6782d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added a fetcher for [LOBID](https://lobid.org/resources/api) resources. [koppor#386](https://github.com/koppor/jabref/issues/386) - When in `biblatex` mode, the [integrity check](https://docs.jabref.org/finding-sorting-and-cleaning-entries/checkintegrity) for journal titles now also checks the field `journal`. - We added support for pushing citations to [TeXShop](https://pages.uoregon.edu/koch/texshop/) on macOS [forum#2699](https://discourse.jabref.org/t/push-to-texshop-mac/2699). +- We added ability to jump to an entry in the command line using -j CITATIONKEY [BIBTEXFILES]. [koppor#540](https://github.com/koppor/jabref/issues/540) ### Changed diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index af568f745cb..55f397f293b 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -974,6 +974,8 @@ Write\ BibTeXEntry\ as\ metadata\ to\ PDF.=Write BibTeXEntry as metadata to PDF. Write\ metadata\ for\ all\ PDFs\ in\ current\ library?=Write metadata for all PDFs in current library? Writing\ metadata...=Writing metadata... +Jump\ to\ the\ entry\ of\ the\ given\ citation\ key.=Jump to the entry of the given citation key. + Embed\ BibTeXEntry\ in\ PDF.=Embed BibTeXEntry in PDF. File\ '%0'\ is\ write\ protected.=File '%0' is write protected. Write\ BibTeXEntry\ as\ XMP\ metadata\ to\ PDF.=Write BibTeXEntry as XMP metadata to PDF. From 6b76bbc8ddae058f2e3096c6d5b69e8138da1aeb Mon Sep 17 00:00:00 2001 From: u7282852 <141634726+u7282852@users.noreply.github.com> Date: Sun, 29 Oct 2023 11:45:01 +1100 Subject: [PATCH 08/11] Update CHANGELOG.md Co-authored-by: Oliver Kopp --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd1b6782d6..e441dbc7029 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added a fetcher for [LOBID](https://lobid.org/resources/api) resources. [koppor#386](https://github.com/koppor/jabref/issues/386) - When in `biblatex` mode, the [integrity check](https://docs.jabref.org/finding-sorting-and-cleaning-entries/checkintegrity) for journal titles now also checks the field `journal`. - We added support for pushing citations to [TeXShop](https://pages.uoregon.edu/koch/texshop/) on macOS [forum#2699](https://discourse.jabref.org/t/push-to-texshop-mac/2699). -- We added ability to jump to an entry in the command line using -j CITATIONKEY [BIBTEXFILES]. [koppor#540](https://github.com/koppor/jabref/issues/540) +- We added ability to jump to an entry in the command line using `-j CITATIONKEY [BIBTEXFILES]`. [koppor#540](https://github.com/koppor/jabref/issues/540) ### Changed From 0179274c2cc664a6a4743fc8c40e52f1b46ce172 Mon Sep 17 00:00:00 2001 From: u7282852 <141634726+u7282852@users.noreply.github.com> Date: Sun, 29 Oct 2023 11:47:38 +1100 Subject: [PATCH 09/11] Update CITEKEY arg name to CITATIONKEY Co-authored-by: Oliver Kopp --- src/main/java/org/jabref/cli/JabRefCLI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index 040405b9cc2..24572a7c939 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -301,7 +301,7 @@ private static Options getOptions() { .longOpt("jumpToKey") .desc(String.format("%s: '%s'", Localization.lang("Jump to the entry of the given citation key."), "-j key")) .hasArg() - .argName("CITEKEY") + .argName("CITATIONKEY") .build()); return options; From d6d17e88afdb53b593e3caab79bbbec51559b91e Mon Sep 17 00:00:00 2001 From: Dane Osborne Date: Sun, 29 Oct 2023 11:58:22 +1100 Subject: [PATCH 10/11] Add comment explaining a previous change --- src/main/java/org/jabref/gui/LibraryTab.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/jabref/gui/LibraryTab.java b/src/main/java/org/jabref/gui/LibraryTab.java index 4e5184bcd71..4d51e1817d0 100644 --- a/src/main/java/org/jabref/gui/LibraryTab.java +++ b/src/main/java/org/jabref/gui/LibraryTab.java @@ -222,6 +222,8 @@ public Node createLoadingAnimationLayout() { public void onDatabaseLoadingStarted() { Node loadingLayout = createLoadingAnimationLayout(); getMainTable().placeholderProperty().setValue(loadingLayout); + // don't raise panel by default as one tab will already be raised. + // See org.jabref.gui.JabRefGui.openDatabases() and org.jabref.gui.importer.actions.OpenDatabasesAction.openFiles() frame.addTab(this, false); } From 6907f80598d16d5d0b9a4dc36f296c429c022a0d Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Wed, 1 Nov 2023 23:28:32 +0100 Subject: [PATCH 11/11] Introduced UiCommands to replace clumsy gui interface --- build.gradle | 6 +- .../org/jabref/cli/ArgumentProcessor.java | 35 ++-- src/main/java/org/jabref/cli/Launcher.java | 13 +- src/main/java/org/jabref/gui/JabRefFrame.java | 128 ++++++++++++++ src/main/java/org/jabref/gui/JabRefGUI.java | 163 +----------------- src/main/java/org/jabref/gui/LibraryTab.java | 2 +- .../java/org/jabref/gui/MainApplication.java | 13 +- .../jabref/gui/remote/CLIMessageHandler.java | 13 +- src/main/java/org/jabref/logic/UiCommand.java | 15 ++ .../jabref/logic/importer/ParserResult.java | 9 - 10 files changed, 189 insertions(+), 208 deletions(-) create mode 100644 src/main/java/org/jabref/logic/UiCommand.java diff --git a/build.gradle b/build.gradle index 594caf871c1..8705f41aaf0 100644 --- a/build.gradle +++ b/build.gradle @@ -41,15 +41,15 @@ group = "org.jabref" version = project.findProperty('projVersion') ?: '100.0.0' java { - sourceCompatibility = JavaVersion.VERSION_19 - targetCompatibility = JavaVersion.VERSION_19 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 // Workaround needed for Eclipse, probably because of https://github.com/gradle/gradle/issues/16922 // Should be removed as soon as Gradle 7.0.1 is released ( https://github.com/gradle/gradle/issues/16922#issuecomment-828217060 ) modularity.inferModulePath.set(false) toolchain { // If this is updated, also update .devcontainer/devcontainer.json#L34 - languageVersion = JavaLanguageVersion.of(20) + languageVersion = JavaLanguageVersion.of(21) } } diff --git a/src/main/java/org/jabref/cli/ArgumentProcessor.java b/src/main/java/org/jabref/cli/ArgumentProcessor.java index 580cd5870df..7016b397cde 100644 --- a/src/main/java/org/jabref/cli/ArgumentProcessor.java +++ b/src/main/java/org/jabref/cli/ArgumentProcessor.java @@ -16,6 +16,7 @@ import org.jabref.gui.externalfiles.AutoSetFileLinksUtil; import org.jabref.gui.undo.NamedCompound; import org.jabref.logic.JabRefException; +import org.jabref.logic.UiCommand; import org.jabref.logic.bibtex.FieldPreferences; import org.jabref.logic.citationkeypattern.CitationKeyGenerator; import org.jabref.logic.exporter.AtomicFileWriter; @@ -64,28 +65,31 @@ import org.slf4j.LoggerFactory; public class ArgumentProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger(ArgumentProcessor.class); - private final JabRefCLI cli; - // Written once by processArguments() - private List parserResults = List.of(); + public enum Mode { INITIAL_START, REMOTE_START } + + private final JabRefCLI cli; private final Mode startupMode; + private final PreferencesService preferencesService; private final FileUpdateMonitor fileUpdateMonitor; private final BibEntryTypesManager entryTypesManager; + private boolean noGUINeeded; + private final List uiCommands = new ArrayList<>(); /** * First call the constructor, then call {@link #processArguments()}. - * Afterward, you can access the {@link #getParserResults()} and other getters. + * Afterward, you can access the {@link #getUiCommands()}. */ public ArgumentProcessor(String[] args, Mode startupMode, PreferencesService preferencesService, FileUpdateMonitor fileUpdateMonitor, - BibEntryTypesManager entryTypesManager) throws org.apache.commons.cli.ParseException { + BibEntryTypesManager entryTypesManager) + throws org.apache.commons.cli.ParseException { this.cli = new JabRefCLI(args); this.startupMode = startupMode; this.preferencesService = preferencesService; @@ -185,11 +189,10 @@ private Optional importFile(Path file, String importFormat) { } } - public List getParserResults() { - return parserResults; - } - public void processArguments() { + uiCommands.clear(); + noGUINeeded = false; + if ((startupMode == Mode.INITIAL_START) && cli.isShowVersion()) { cli.displayVersion(); } @@ -197,7 +200,6 @@ public void processArguments() { if ((startupMode == Mode.INITIAL_START) && cli.isHelp()) { JabRefCLI.printUsage(preferencesService); noGUINeeded = true; - this.parserResults = Collections.emptyList(); return; } @@ -221,7 +223,6 @@ public void processArguments() { if (cli.isExportMatches()) { if (!loaded.isEmpty()) { if (!exportMatches(loaded)) { - this.parserResults = Collections.emptyList(); return; } } else { @@ -281,7 +282,9 @@ public void processArguments() { jumpToKey(loaded, cli.getJumpToKey()); } - this.parserResults = loaded; + if (!cli.isBlank() && !loaded.isEmpty()) { + uiCommands.add(new UiCommand.OpenDatabases(loaded)); + } } private void writeMetadataToPdf(List loaded, @@ -781,7 +784,7 @@ private void jumpToKey(List loaded, String citationKey) { for (ParserResult parserResult : loaded) { Optional entry = parserResult.getDatabase().getEntryByCitationKey(citationKey); if (entry.isPresent()) { - parserResult.setEntryToFocus(entry.get()); + uiCommands.add(new UiCommand.JumpToEntryKey(parserResult, entry.get())); return; } } @@ -796,7 +799,7 @@ public boolean shouldShutDown() { return cli.isDisableGui() || cli.isShowVersion() || noGUINeeded; } - public enum Mode { - INITIAL_START, REMOTE_START + public List getUiCommands() { + return uiCommands; } } diff --git a/src/main/java/org/jabref/cli/Launcher.java b/src/main/java/org/jabref/cli/Launcher.java index a49ea92e865..6ec7a99f644 100644 --- a/src/main/java/org/jabref/cli/Launcher.java +++ b/src/main/java/org/jabref/cli/Launcher.java @@ -6,11 +6,14 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.Map; import org.jabref.gui.Globals; import org.jabref.gui.MainApplication; +import org.jabref.logic.UiCommand; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.ProxyAuthenticator; @@ -100,7 +103,15 @@ public static void main(String[] args) { System.exit(0); } - MainApplication.main(argumentProcessor.getParserResults(), argumentProcessor.isBlank(), preferences, fileUpdateMonitor, ARGUMENTS); + List uiCommands = new ArrayList<>(argumentProcessor.getUiCommands()); + List lastFiles = preferences.getGuiPreferences().getLastFilesOpened(); + if (!argumentProcessor.isBlank() && preferences.getWorkspacePreferences().shouldOpenLastEdited() && !lastFiles.isEmpty()) { + for (String file : lastFiles) { + uiCommands.add(new UiCommand.OpenDatabaseFromPath(Path.of(file))); + } + } + + MainApplication.main(uiCommands, preferences, fileUpdateMonitor, ARGUMENTS); } catch (ParseException e) { LOGGER.error("Problem parsing arguments", e); JabRefCLI.printUsage(preferences); diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 3dff38bafbb..c34a1bd6278 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -44,6 +45,7 @@ import org.jabref.gui.help.HelpAction; import org.jabref.gui.importer.ImportEntriesDialog; import org.jabref.gui.importer.NewEntryAction; +import org.jabref.gui.importer.ParserResultWarningDialog; import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; @@ -57,11 +59,15 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.UiCommand; import org.jabref.logic.help.HelpFile; import org.jabref.logic.importer.ImportCleanup; import org.jabref.logic.importer.ParserResult; import org.jabref.logic.l10n.Localization; import org.jabref.logic.shared.DatabaseLocation; +import org.jabref.logic.shared.DatabaseNotSupportedException; +import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; +import org.jabref.logic.shared.exception.NotASharedDatabaseException; import org.jabref.logic.undo.AddUndoableActionEvent; import org.jabref.logic.undo.UndoChangeEvent; import org.jabref.logic.undo.UndoRedoEvent; @@ -958,6 +964,128 @@ public Stage getMainStage() { return mainStage; } + public void handleUiCommands(List uiCommands) { + for (UiCommand uiCommand : uiCommands) { + switch (uiCommand) { + case UiCommand.OpenDatabaseFromPath command -> + getOpenDatabaseAction().openFile(command.path()); + case UiCommand.JumpToEntryKey jumpToEntryKey -> { + Optional libraryTab = getLibraryTabs().stream() + .filter(tab -> tab.getDatabase() + .equals(jumpToEntryKey.parserResult() + .getDatabase())) + .findFirst(); + libraryTab.ifPresent(tab -> { + tab.clearAndSelect(jumpToEntryKey.bibEntry()); + showLibraryTab(tab); + }); + } + case UiCommand.OpenDatabases command -> + openDatabases(command.parserResults()); + } + } + } + + private void openDatabases(List parserResults) { + final List toOpenTab = new ArrayList<>(); + + // Remove invalid databases + List invalidDatabases = parserResults.stream() + .filter(ParserResult::isInvalid) + .toList(); + final List failed = new ArrayList<>(invalidDatabases); + parserResults.removeAll(invalidDatabases); + + // passed file (we take the first one) should be focused + Path focusedFile = parserResults.stream() + .findFirst() + .flatMap(ParserResult::getPath) + .orElse(prefs.getGuiPreferences() + .getLastFocusedFile()) + .toAbsolutePath(); + + // Add all bibDatabases databases to the frame: + boolean first = false; + for (ParserResult pr : parserResults) { + // Define focused tab + if (pr.getPath().filter(path -> path.toAbsolutePath().equals(focusedFile)).isPresent()) { + first = true; + } + + if (pr.getDatabase().isShared()) { + try { + OpenDatabaseAction.openSharedDatabase( + pr, + this, + dialogService, + prefs, + stateManager, + entryTypesManager, + fileUpdateMonitor, + undoManager, + Globals.TASK_EXECUTOR); + } catch ( + SQLException | + DatabaseNotSupportedException | + InvalidDBMSConnectionPropertiesException | + NotASharedDatabaseException e) { + + LOGGER.error("Connection error", e); + dialogService.showErrorDialogAndWait( + Localization.lang("Connection error"), + Localization.lang("A local copy will be opened."), + e); + toOpenTab.add(pr); + } + } else if (pr.toOpenTab()) { + // things to be appended to an opened tab should be done after opening all tabs + // add them to the list + toOpenTab.add(pr); + } else { + addTab(pr, first); + first = false; + } + } + + // finally add things to the currently opened tab + for (ParserResult parserResult : toOpenTab) { + addTab(parserResult, first); + first = false; + } + + for (ParserResult pr : failed) { + String message = Localization.lang("Error opening file '%0'", + pr.getPath().map(Path::toString).orElse("(File name unknown)")) + "\n" + + pr.getErrorMessage(); + + dialogService.showErrorDialogAndWait(Localization.lang("Error opening file"), message); + } + + // Display warnings, if any + int tabNumber = 0; + for (ParserResult pr : parserResults) { + ParserResultWarningDialog.showParserResultWarningDialog(pr, this, tabNumber++); + } + + // After adding the databases, go through each and see if + // any post open actions need to be done. For instance, checking + // if we found new entry types that can be imported, or checking + // if the database contents should be modified due to new features + // in this version of JabRef. + // Note that we have to check whether i does not go over getBasePanelCount(). + // This is because importToOpen might have been used, which adds to + // loadedDatabases, but not to getBasePanelCount() + + for (int i = 0; (i < parserResults.size()) && (i < getBasePanelCount()); i++) { + ParserResult pr = parserResults.get(i); + LibraryTab libraryTab = getLibraryTabAt(i); + + OpenDatabaseAction.performPostOpenActions(libraryTab, pr); + } + + LOGGER.debug("Finished adding panels"); + } + /** * The action concerned with closing the window. */ diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java index a4ee050527e..efca0cb8bfa 100644 --- a/src/main/java/org/jabref/gui/JabRefGUI.java +++ b/src/main/java/org/jabref/gui/JabRefGUI.java @@ -1,13 +1,8 @@ package org.jabref.gui; -import java.nio.file.Path; -import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; -import javafx.application.Platform; import javafx.scene.Scene; import javafx.scene.input.KeyEvent; import javafx.stage.Screen; @@ -15,17 +10,11 @@ import org.jabref.gui.help.VersionWorker; import org.jabref.gui.icon.IconTheme; -import org.jabref.gui.importer.ParserResultWarningDialog; -import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.keyboard.TextInputKeyBindings; -import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.UiCommand; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.ProxyRegisterer; -import org.jabref.logic.shared.DatabaseNotSupportedException; -import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; -import org.jabref.logic.shared.exception.NotASharedDatabaseException; import org.jabref.logic.util.WebViewStore; -import org.jabref.model.entry.BibEntry; import org.jabref.model.strings.StringUtil; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.GuiPreferences; @@ -45,19 +34,14 @@ public class JabRefGUI { private final PreferencesService preferencesService; private final FileUpdateMonitor fileUpdateMonitor; - private final List parserResults; - private final boolean isBlank; + private final List uiCommands; private boolean correctedWindowPos; - private final List failed = new ArrayList<>(); - private final List toOpenTab = new ArrayList<>(); public JabRefGUI(Stage mainStage, - List databases, - boolean isBlank, + List uiCommands, PreferencesService preferencesService, FileUpdateMonitor fileUpdateMonitor) { - this.parserResults = databases; - this.isBlank = isBlank; + this.uiCommands = uiCommands; this.preferencesService = preferencesService; this.fileUpdateMonitor = fileUpdateMonitor; this.correctedWindowPos = false; @@ -167,7 +151,7 @@ private void openWindow(Stage mainStage) { event.consume(); } }); - Platform.runLater(this::openDatabases); + mainFrame.handleUiCommands(uiCommands); if (!(fileUpdateMonitor.isActive())) { getMainFrame().getDialogService() @@ -177,133 +161,6 @@ private void openWindow(Stage mainStage) { } } - /** - * ToDo: This should be part of JabRefFrame - */ - private void openDatabases() { - // If the option is enabled, open the last edited libraries, if any. - if (!isBlank && preferencesService.getWorkspacePreferences().shouldOpenLastEdited()) { - openLastEditedDatabases(); - } - - // From here on, the libraries provided by command line arguments are treated - - // Remove invalid databases - List invalidDatabases = parserResults.stream() - .filter(ParserResult::isInvalid) - .toList(); - failed.addAll(invalidDatabases); - parserResults.removeAll(invalidDatabases); - - // passed file (we take the first one) should be focused - Path focusedFile = parserResults.stream() - .findFirst() - .flatMap(ParserResult::getPath) - .orElse(preferencesService.getGuiPreferences() - .getLastFocusedFile()) - .toAbsolutePath(); - // check whether there is a jump to entry and need to focus different file - boolean focusDifferent = false; - Optional focusedEntry = Optional.empty(); - for (ParserResult parserResult : parserResults) { - // Make sure this parser result is its own library instead of imported BibTeX entries - if (parserResult.getEntryToFocus().isPresent() && !parserResult.toOpenTab()) { - focusDifferent = true; - focusedEntry = parserResult.getEntryToFocus(); - break; - } - } - - // Add all bibDatabases databases to the frame: - boolean first = false; - for (ParserResult parserResult : parserResults) { - // Define focused tab - if (parserResult.getPath().filter(path -> path.toAbsolutePath().equals(focusedFile)).isPresent() && !focusDifferent) { - first = true; - } - if (parserResult.getEntryToFocus().isPresent() && focusDifferent) { - first = true; - focusDifferent = false; - } - - if (parserResult.getDatabase().isShared()) { - try { - OpenDatabaseAction.openSharedDatabase( - parserResult, - mainFrame, - mainFrame.getDialogService(), - preferencesService, - Globals.stateManager, - Globals.entryTypesManager, - fileUpdateMonitor, - mainFrame.getUndoManager(), - Globals.TASK_EXECUTOR); - } catch (SQLException | - DatabaseNotSupportedException | - InvalidDBMSConnectionPropertiesException | - NotASharedDatabaseException e) { - - LOGGER.error("Connection error", e); - mainFrame.getDialogService().showErrorDialogAndWait( - Localization.lang("Connection error"), - Localization.lang("A local copy will be opened."), - e); - toOpenTab.add(parserResult); - } - } else if (parserResult.toOpenTab()) { - // things to be appended to an opened tab should be done after opening all tabs - // add them to the list - toOpenTab.add(parserResult); - } else { - mainFrame.addTab(parserResult, first); - first = false; - } - } - - // finally add things to the currently opened tab - for (ParserResult parserResult : toOpenTab) { - mainFrame.addTab(parserResult, first); - first = false; - } - - for (ParserResult pr : failed) { - String message = Localization.lang("Error opening file '%0'", - pr.getPath().map(Path::toString).orElse("(File name unknown)")) + "\n" + - pr.getErrorMessage(); - - mainFrame.getDialogService().showErrorDialogAndWait(Localization.lang("Error opening file"), message); - } - - // Display warnings, if any - int tabNumber = 0; - for (ParserResult pr : parserResults) { - ParserResultWarningDialog.showParserResultWarningDialog(pr, mainFrame, tabNumber++); - } - - // After adding the databases, go through each and see if - // any post open actions need to be done. For instance, checking - // if we found new entry types that can be imported, or checking - // if the database contents should be modified due to new features - // in this version of JabRef. - // Note that we have to check whether i does not go over getBasePanelCount(). - // This is because importToOpen might have been used, which adds to - // loadedDatabases, but not to getBasePanelCount() - - for (int i = 0; (i < parserResults.size()) && (i < mainFrame.getBasePanelCount()); i++) { - ParserResult pr = parserResults.get(i); - LibraryTab libraryTab = mainFrame.getLibraryTabAt(i); - - OpenDatabaseAction.performPostOpenActions(libraryTab, pr); - } - // focus a particular entry if CLI has received a jump to entry key command - if (focusedEntry.isPresent()) { - mainFrame.getCurrentLibraryTab().clearAndSelect(focusedEntry.get()); - mainFrame.showLibraryTab(mainFrame.getCurrentLibraryTab()); - } - - LOGGER.debug("Finished adding panels"); - } - private void saveWindowState(Stage mainStage) { GuiPreferences preferences = preferencesService.getGuiPreferences(); preferences.setPositionX(mainStage.getX()); @@ -343,16 +200,6 @@ private boolean isWindowPositionOutOfBounds() { preferencesService.getGuiPreferences().getPositionY()); } - private void openLastEditedDatabases() { - List lastFiles = preferencesService.getGuiPreferences().getLastFilesOpened(); - if (lastFiles.isEmpty()) { - return; - } - - List filesToOpen = lastFiles.stream().map(Path::of).collect(Collectors.toList()); - getMainFrame().getOpenDatabaseAction().openFiles(filesToOpen); - } - public static JabRefFrame getMainFrame() { return mainFrame; } diff --git a/src/main/java/org/jabref/gui/LibraryTab.java b/src/main/java/org/jabref/gui/LibraryTab.java index 4d51e1817d0..eac9c68a564 100644 --- a/src/main/java/org/jabref/gui/LibraryTab.java +++ b/src/main/java/org/jabref/gui/LibraryTab.java @@ -224,7 +224,7 @@ public void onDatabaseLoadingStarted() { getMainTable().placeholderProperty().setValue(loadingLayout); // don't raise panel by default as one tab will already be raised. // See org.jabref.gui.JabRefGui.openDatabases() and org.jabref.gui.importer.actions.OpenDatabasesAction.openFiles() - frame.addTab(this, false); + frame.addTab(this, true); } public void onDatabaseLoadingSucceed(ParserResult result) { diff --git a/src/main/java/org/jabref/gui/MainApplication.java b/src/main/java/org/jabref/gui/MainApplication.java index a187843977d..5f49d28d83d 100644 --- a/src/main/java/org/jabref/gui/MainApplication.java +++ b/src/main/java/org/jabref/gui/MainApplication.java @@ -6,7 +6,7 @@ import javafx.stage.Stage; import org.jabref.gui.openoffice.OOBibBaseConnect; -import org.jabref.logic.importer.ParserResult; +import org.jabref.logic.UiCommand; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.JabRefPreferences; @@ -14,18 +14,15 @@ * JabRef's main class to process command line options and to start the UI */ public class MainApplication extends Application { - private static List parserResults; - private static boolean isBlank; + private static List uiCommands; private static JabRefPreferences preferences; private static FileUpdateMonitor fileUpdateMonitor; - public static void main(List parserResults, - boolean blank, + public static void main(List uiCommands, JabRefPreferences preferences, FileUpdateMonitor fileUpdateMonitor, String[] args) { - MainApplication.parserResults = parserResults; - MainApplication.isBlank = blank; + MainApplication.uiCommands = uiCommands; MainApplication.preferences = preferences; MainApplication.fileUpdateMonitor = fileUpdateMonitor; launch(args); @@ -35,7 +32,7 @@ public static void main(List parserResults, public void start(Stage mainStage) { FallbackExceptionHandler.installExceptionHandler(); Globals.startBackgroundTasks(); - new JabRefGUI(mainStage, parserResults, isBlank, preferences, fileUpdateMonitor); + new JabRefGUI(mainStage, uiCommands, preferences, fileUpdateMonitor); } @Override diff --git a/src/main/java/org/jabref/gui/remote/CLIMessageHandler.java b/src/main/java/org/jabref/gui/remote/CLIMessageHandler.java index 272d84fd600..8073847ee4f 100644 --- a/src/main/java/org/jabref/gui/remote/CLIMessageHandler.java +++ b/src/main/java/org/jabref/gui/remote/CLIMessageHandler.java @@ -1,12 +1,9 @@ package org.jabref.gui.remote; -import java.util.List; - import javafx.application.Platform; import org.jabref.cli.ArgumentProcessor; import org.jabref.gui.JabRefGUI; -import org.jabref.logic.importer.ParserResult; import org.jabref.logic.remote.server.RemoteMessageHandler; import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.util.FileUpdateMonitor; @@ -39,15 +36,7 @@ public void handleCommandLineArguments(String[] message) { fileUpdateMonitor, entryTypesManager); argumentProcessor.processArguments(); - List loaded = argumentProcessor.getParserResults(); - for (int i = 0; i < loaded.size(); i++) { - ParserResult pr = loaded.get(i); - boolean focusPanel = i == 0; - Platform.runLater(() -> - // Need to run this on the JavaFX thread - JabRefGUI.getMainFrame().addTab(pr, focusPanel) - ); - } + Platform.runLater(() -> JabRefGUI.getMainFrame().handleUiCommands(argumentProcessor.getUiCommands())); } catch (ParseException e) { LOGGER.error("Error when parsing CLI args", e); } diff --git a/src/main/java/org/jabref/logic/UiCommand.java b/src/main/java/org/jabref/logic/UiCommand.java new file mode 100644 index 00000000000..e574a4a8e6e --- /dev/null +++ b/src/main/java/org/jabref/logic/UiCommand.java @@ -0,0 +1,15 @@ +package org.jabref.logic; + +import java.nio.file.Path; +import java.util.List; + +import org.jabref.logic.importer.ParserResult; +import org.jabref.model.entry.BibEntry; + +public sealed interface UiCommand { + record JumpToEntryKey(ParserResult parserResult, BibEntry bibEntry) implements UiCommand { } + + record OpenDatabases(List parserResults) implements UiCommand { } + + record OpenDatabaseFromPath(Path path) implements UiCommand { } +} diff --git a/src/main/java/org/jabref/logic/importer/ParserResult.java b/src/main/java/org/jabref/logic/importer/ParserResult.java index a700696ebb9..2f134224562 100644 --- a/src/main/java/org/jabref/logic/importer/ParserResult.java +++ b/src/main/java/org/jabref/logic/importer/ParserResult.java @@ -26,7 +26,6 @@ public class ParserResult { private boolean invalid; private boolean toOpenTab; private boolean changedOnMigration = false; - private BibEntry entryToFocus; public ParserResult() { this(Collections.emptyList()); @@ -100,14 +99,6 @@ public void setPath(Path path) { file = path; } - public Optional getEntryToFocus() { - return Optional.ofNullable(entryToFocus); - } - - public void setEntryToFocus(BibEntry bibEntry) { - entryToFocus = bibEntry; - } - /** * Add a parser warning. *