diff --git a/CHANGELOG.md b/CHANGELOG.md index 59eea617342..0a5f6b98411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We readded the possibility to keep the search string when switching tabs. It is implemented by a toggle button. [#4096](https://github.com/JabRef/jabref/issues/4096#issuecomment-575986882) - We allowed the user to also preview the available citation styles in the preferences besides the selected ones [#8108](https://github.com/JabRef/jabref/issues/8108) - We added an option to search the available citation styles by name in the preferences [#8108](https://github.com/JabRef/jabref/issues/8108) +- We added an option to generate bib-entries from ID through a popover in the toolbar. [#4183](https://github.com/JabRef/jabref/issues/4183) ### Changed diff --git a/src/main/java/org/jabref/gui/EntryTypeViewModel.java b/src/main/java/org/jabref/gui/EntryTypeViewModel.java index d8221b328e6..9318c56d8d0 100644 --- a/src/main/java/org/jabref/gui/EntryTypeViewModel.java +++ b/src/main/java/org/jabref/gui/EntryTypeViewModel.java @@ -153,7 +153,7 @@ public void runFetcherWorker() { ImportCleanup cleanup = new ImportCleanup(libraryTab.getBibDatabaseContext().getMode()); cleanup.doPostCleanup(entry); Optional duplicate = new DuplicateCheck(Globals.entryTypesManager).containsDuplicate(libraryTab.getDatabase(), entry, libraryTab.getBibDatabaseContext().getMode()); - if ((duplicate.isPresent())) { + if (duplicate.isPresent()) { DuplicateResolverDialog dialog = new DuplicateResolverDialog(entry, duplicate.get(), DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, libraryTab.getBibDatabaseContext(), stateManager); switch (dialogService.showCustomDialogAndWait(dialog).orElse(DuplicateResolverDialog.DuplicateResolverResult.BREAK)) { case KEEP_LEFT: diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 7a262d5981b..7227e0de601 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -86,6 +86,8 @@ import org.jabref.gui.help.ErrorConsoleAction; import org.jabref.gui.help.HelpAction; import org.jabref.gui.help.SearchForUpdateAction; +import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.importer.GenerateEntryFromIdDialog; import org.jabref.gui.importer.ImportCommand; import org.jabref.gui.importer.ImportEntriesDialog; import org.jabref.gui.importer.NewDatabaseAction; @@ -174,6 +176,7 @@ public class JabRefFrame extends BorderPane { private SidePane sidePane; private TabPane tabbedPane; private PopOver progressViewPopOver; + private PopOver entryFromIdPopOver; private final TaskExecutor taskExecutor; @@ -477,6 +480,8 @@ private Node createToolbar() { final Button pushToApplicationButton = factory.createIconButton(pushToApplicationAction.getActionInformation(), pushToApplicationAction); pushToApplicationsManager.registerReconfigurable(pushToApplicationButton); + // Setup Toolbar + ToolBar toolBar = new ToolBar( new HBox( @@ -493,6 +498,7 @@ private Node createToolbar() { new HBox( factory.createIconButton(StandardActions.NEW_ARTICLE, new NewEntryAction(this, StandardEntryType.Article, dialogService, prefs, stateManager)), factory.createIconButton(StandardActions.NEW_ENTRY, new NewEntryAction(this, dialogService, prefs, stateManager)), + createNewEntryFromIdButton(), factory.createIconButton(StandardActions.NEW_ENTRY_FROM_PLAIN_TEXT, new ExtractBibtexAction(dialogService, prefs, stateManager)), factory.createIconButton(StandardActions.DELETE_ENTRY, new EditAction(StandardActions.DELETE_ENTRY, this, stateManager)) ), @@ -907,6 +913,36 @@ private MenuBar createMenu() { return menu; } + private Button createNewEntryFromIdButton() { + Button newEntryFromIdButton = new Button(); + + newEntryFromIdButton.setGraphic(IconTheme.JabRefIcons.IMPORT.getGraphicNode()); + newEntryFromIdButton.getStyleClass().setAll("icon-button"); + newEntryFromIdButton.setFocusTraversable(false); + newEntryFromIdButton.disableProperty().bind(ActionHelper.needsDatabase(stateManager).not()); + newEntryFromIdButton.setOnMouseClicked(event -> { + GenerateEntryFromIdDialog entryFromId = new GenerateEntryFromIdDialog(getCurrentLibraryTab(), dialogService, prefs, taskExecutor); + + if (entryFromIdPopOver == null) { + entryFromIdPopOver = new PopOver(entryFromId.getDialogPane()); + entryFromIdPopOver.setTitle(Localization.lang("Import by ID")); + entryFromIdPopOver.setArrowLocation(PopOver.ArrowLocation.TOP_CENTER); + entryFromIdPopOver.setContentNode(entryFromId.getDialogPane()); + entryFromIdPopOver.show(newEntryFromIdButton); + entryFromId.setEntryFromIdPopOver(entryFromIdPopOver); + } else if (entryFromIdPopOver.isShowing()) { + entryFromIdPopOver.hide(); + } else { + entryFromIdPopOver.setContentNode(entryFromId.getDialogPane()); + entryFromIdPopOver.show(newEntryFromIdButton); + entryFromId.setEntryFromIdPopOver(entryFromIdPopOver); + } + }); + newEntryFromIdButton.setTooltip(new Tooltip(Localization.lang("Import by ID"))); + + return newEntryFromIdButton; + } + private Group createTaskIndicator() { ProgressIndicator indicator = new ProgressIndicator(); indicator.getStyleClass().add("progress-indicatorToolbar"); diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index cbe51b9db9e..9c2b75fe9e1 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -131,7 +131,6 @@ public enum StandardActions implements Action { LIBRARY_PROPERTIES(Localization.lang("Library properties")), EDIT_PREAMBLE(Localization.lang("Edit preamble")), EDIT_STRINGS(Localization.lang("Edit string constants"), IconTheme.JabRefIcons.EDIT_STRINGS, KeyBinding.EDIT_STRINGS), - FIND_DUPLICATES(Localization.lang("Find duplicates"), IconTheme.JabRefIcons.FIND_DUPLICATES), MERGE_ENTRIES(Localization.lang("Merge entries"), IconTheme.JabRefIcons.MERGE_ENTRIES, KeyBinding.MERGE_ENTRIES), RESOLVE_DUPLICATE_KEYS(Localization.lang("Resolve duplicate citation keys"), Localization.lang("Find and remove duplicate citation keys"), KeyBinding.RESOLVE_DUPLICATE_CITATION_KEYS), diff --git a/src/main/java/org/jabref/gui/importer/GenerateEntryFromIdAction.java b/src/main/java/org/jabref/gui/importer/GenerateEntryFromIdAction.java new file mode 100644 index 00000000000..f02fa00a327 --- /dev/null +++ b/src/main/java/org/jabref/gui/importer/GenerateEntryFromIdAction.java @@ -0,0 +1,89 @@ +package org.jabref.gui.importer; + +import java.util.Optional; + +import org.jabref.gui.DialogService; +import org.jabref.gui.Globals; +import org.jabref.gui.LibraryTab; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.util.BackgroundTask; +import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.JabRefException; +import org.jabref.logic.database.DuplicateCheck; +import org.jabref.logic.importer.CompositeIdFetcher; +import org.jabref.logic.importer.FetcherException; +import org.jabref.logic.importer.ImportCleanup; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.BibEntry; +import org.jabref.preferences.PreferencesService; + +import org.controlsfx.control.PopOver; + +public class GenerateEntryFromIdAction extends SimpleCommand { + + private final LibraryTab libraryTab; + private final DialogService dialogService; + private final PreferencesService preferencesService; + private final String identifier; + private final TaskExecutor taskExecutor; + private final PopOver entryFromIdPopOver; + + public GenerateEntryFromIdAction(LibraryTab libraryTab, DialogService dialogService, PreferencesService preferencesService, TaskExecutor taskExecutor, PopOver entryFromIdPopOver, String identifier) { + this.libraryTab = libraryTab; + this.dialogService = dialogService; + this.preferencesService = preferencesService; + this.identifier = identifier; + this.taskExecutor = taskExecutor; + this.entryFromIdPopOver = entryFromIdPopOver; + } + + @Override + public void execute() { + BackgroundTask> backgroundTask = searchAndImportEntryInBackground(); + backgroundTask.titleProperty().set(Localization.lang("Import by ID")); + backgroundTask.showToUser(true); + backgroundTask.onRunning(() -> dialogService.notify("%s".formatted(backgroundTask.messageProperty().get()))); + backgroundTask.onFailure((e) -> dialogService.notify(e.getMessage())); + backgroundTask.onSuccess((bibEntry) -> bibEntry.ifPresentOrElse((entry) -> { + libraryTab.insertEntry(entry); + entryFromIdPopOver.hide(); + dialogService.notify(Localization.lang("Imported one entry")); + }, + () -> dialogService.notify(Localization.lang("Import canceled")) + )); + backgroundTask.executeWith(taskExecutor); + } + + private BackgroundTask> searchAndImportEntryInBackground() { + return new BackgroundTask<>() { + @Override + protected Optional call() throws JabRefException { + if (isCanceled()) { + return Optional.empty(); + } + + updateMessage(Localization.lang("Searching...")); + try { + Optional result = new CompositeIdFetcher(preferencesService.getImportFormatPreferences()).performSearchById(identifier); + if (result.isPresent()) { + final BibEntry entry = result.get(); + ImportCleanup cleanup = new ImportCleanup(libraryTab.getBibDatabaseContext().getMode()); + cleanup.doPostCleanup(entry); + // DuplicateCheck only covers DOI and ISBN at the moment. + Optional duplicate = new DuplicateCheck(Globals.entryTypesManager).containsDuplicate(libraryTab.getDatabase(), entry, libraryTab.getBibDatabaseContext().getMode()); + if (duplicate.isPresent()) { + throw new JabRefException(Localization.lang("Entry already exists")); + } + } else { + throw new JabRefException(Localization.lang("Could not find any bibliographic information.")); + } + updateMessage(Localization.lang("Imported one entry")); + return result; + } catch (FetcherException fetcherException) { + throw new JabRefException("Fetcher error: %s".formatted(fetcherException.getMessage())); + } + } + }; + } + +} diff --git a/src/main/java/org/jabref/gui/importer/GenerateEntryFromIdDialog.fxml b/src/main/java/org/jabref/gui/importer/GenerateEntryFromIdDialog.fxml new file mode 100644 index 00000000000..ed68c2425c7 --- /dev/null +++ b/src/main/java/org/jabref/gui/importer/GenerateEntryFromIdDialog.fxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + +