diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0638fbea9..de4f00f3f07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added "Close library" to the File menu. [#14381](https://github.com/JabRef/jabref/issues/14381) - We added a "Regenerate" button for the AI chat allowing the user to make the language model reformulate its response to the previous prompt. [#12191](https://github.com/JabRef/jabref/issues/12191) - We added support for transliteration of fields to English and automatic transliteration of generated citation key. [#11377](https://github.com/JabRef/jabref/issues/11377) +- We added support for "Search Google Scholar" and "Search Semantic Scholar" to quickly search for a selected entry's title in Google Scholar or Semantic Scholar directly from the main table's context menu [#12268](https://github.com/JabRef/jabref/issues/12268) +- We introduced a new "Search Engine URL Template" setting in Preferences to allow users to customize their search engine URL templates [#12268](https://github.com/JabRef/jabref/issues/12268) ### Changed @@ -32,6 +34,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We separated the "Clean up entries" dialog into three tabs for clarity [#13819](https://github.com/JabRef/jabref/issues/13819) - `JabKit`: `--porcelain` does not output any logs to the console anymore. [#14244](https://github.com/JabRef/jabref/pull/14244) - Ctrl + Shift + L now opens the terminal in the active library directory. [#14130](https://github.com/JabRef/jabref/issues/14130) +- The URL integrity check now checks the complete URL syntax. [#14370](https://github.com/JabRef/jabref/pull/14370) - We changed fixed-value ComboBoxes to SearchableComboBox for better usability. [#14083](https://github.com/JabRef/jabref/issues/14083) ### Fixed diff --git a/jabgui/src/main/java/org/jabref/gui/actions/StandardActions.java b/jabgui/src/main/java/org/jabref/gui/actions/StandardActions.java index 0c37633c8c4..97a008e366b 100644 --- a/jabgui/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/jabgui/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -44,6 +44,9 @@ public enum StandardActions implements Action { EXTRACT_FILE_REFERENCES_ONLINE(Localization.lang("Extract references from file (online)"), IconTheme.JabRefIcons.FILE_STAR), EXTRACT_FILE_REFERENCES_OFFLINE(Localization.lang("Extract references from file (offline)"), IconTheme.JabRefIcons.FILE_STAR), OPEN_URL(Localization.lang("Open URL or DOI"), IconTheme.JabRefIcons.WWW, KeyBinding.OPEN_URL_OR_DOI), + SEARCH(Localization.lang("Search...")), + SEARCH_GOOGLE_SCHOLAR(Localization.lang("Search Google Scholar")), + SEARCH_SEMANTIC_SCHOLAR(Localization.lang("Search Semantic Scholar")), SEARCH_SHORTSCIENCE(Localization.lang("Search ShortScience")), MERGE_WITH_FETCHED_ENTRY(Localization.lang("Get bibliographic data from %0", "DOI/ISBN/..."), KeyBinding.MERGE_WITH_FETCHED_ENTRY), BATCH_MERGE_WITH_FETCHED_ENTRY(Localization.lang("Get bibliographic data from %0 (fully automated)", "DOI/ISBN/...")), diff --git a/jabgui/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/jabgui/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index 16d67dcaf49..1cf96ef1993 100644 --- a/jabgui/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/jabgui/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -99,7 +99,8 @@ public static ContextMenu create(BibEntryTableViewModel entry, extractFileReferencesOffline, factory.createMenuItem(StandardActions.OPEN_URL, new OpenUrlAction(dialogService, stateManager, preferences)), - factory.createMenuItem(StandardActions.SEARCH_SHORTSCIENCE, new SearchShortScienceAction(dialogService, stateManager, preferences)), + + createSearchSubMenu(factory, dialogService, stateManager, preferences), new SeparatorMenuItem(), @@ -237,4 +238,17 @@ private static Menu createSendSubMenu(ActionFactory factory, return sendMenu; } + + private static Menu createSearchSubMenu(ActionFactory factory, + DialogService dialogService, + StateManager stateManager, + GuiPreferences preferences) { + Menu searchMenu = factory.createMenu(StandardActions.SEARCH); + searchMenu.getItems().addAll( + factory.createMenuItem(StandardActions.SEARCH_GOOGLE_SCHOLAR, new SearchGoogleScholarAction(dialogService, stateManager, preferences)), + factory.createMenuItem(StandardActions.SEARCH_SEMANTIC_SCHOLAR, new SearchSemanticScholarAction(dialogService, stateManager, preferences)), + factory.createMenuItem(StandardActions.SEARCH_SHORTSCIENCE, new SearchShortScienceAction(dialogService, stateManager, preferences)) + ); + return searchMenu; + } } diff --git a/jabgui/src/main/java/org/jabref/gui/maintable/SearchGoogleScholarAction.java b/jabgui/src/main/java/org/jabref/gui/maintable/SearchGoogleScholarAction.java new file mode 100644 index 00000000000..b9cfd17c941 --- /dev/null +++ b/jabgui/src/main/java/org/jabref/gui/maintable/SearchGoogleScholarAction.java @@ -0,0 +1,57 @@ +package org.jabref.gui.maintable; + +import java.io.IOException; +import java.util.List; + +import javafx.beans.binding.BooleanExpression; + +import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.desktop.os.NativeDesktop; +import org.jabref.gui.preferences.GuiPreferences; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.util.ExternalLinkCreator; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.jabref.gui.actions.ActionHelper.isFieldSetForSelectedEntry; +import static org.jabref.gui.actions.ActionHelper.needsEntriesSelected; + +public class SearchGoogleScholarAction extends SimpleCommand { + private static final Logger LOGGER = LoggerFactory.getLogger(SearchGoogleScholarAction.class); + + private final DialogService dialogService; + private final StateManager stateManager; + private final GuiPreferences preferences; + private final ExternalLinkCreator externalLinkCreator; + + public SearchGoogleScholarAction(DialogService dialogService, StateManager stateManager, GuiPreferences preferences) { + this.dialogService = dialogService; + this.stateManager = stateManager; + this.preferences = preferences; + + this.externalLinkCreator = new ExternalLinkCreator(preferences.getImporterPreferences()); + + BooleanExpression fieldIsSet = isFieldSetForSelectedEntry(StandardField.TITLE, stateManager); + this.executable.bind(needsEntriesSelected(1, stateManager).and(fieldIsSet)); + } + + @Override + public void execute() { + stateManager.getActiveDatabase().ifPresent(databaseContext -> { + final List bibEntries = stateManager.getSelectedEntries(); + externalLinkCreator.getGoogleScholarSearchURL(bibEntries.getFirst()).ifPresent(url -> { + try { + NativeDesktop.openExternalViewer(databaseContext, preferences, url, StandardField.URL, dialogService, bibEntries.getFirst()); + } catch (IOException ex) { + LOGGER.warn("Could not open Google Scholar", ex); + dialogService.notify(Localization.lang("Unable to open Google Scholar.") + " " + ex.getMessage()); + } + }); + }); + } +} diff --git a/jabgui/src/main/java/org/jabref/gui/maintable/SearchSemanticScholarAction.java b/jabgui/src/main/java/org/jabref/gui/maintable/SearchSemanticScholarAction.java new file mode 100644 index 00000000000..9d276a344fb --- /dev/null +++ b/jabgui/src/main/java/org/jabref/gui/maintable/SearchSemanticScholarAction.java @@ -0,0 +1,55 @@ +package org.jabref.gui.maintable; + +import java.io.IOException; +import java.util.List; + +import javafx.beans.binding.BooleanExpression; + +import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.desktop.os.NativeDesktop; +import org.jabref.gui.preferences.GuiPreferences; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.util.ExternalLinkCreator; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SearchSemanticScholarAction extends SimpleCommand { + private static final Logger LOGGER = LoggerFactory.getLogger(SearchSemanticScholarAction.class); + + private final DialogService dialogService; + private final StateManager stateManager; + private final GuiPreferences preferences; + private final ExternalLinkCreator externalLinkCreator; + + public SearchSemanticScholarAction(DialogService dialogService, StateManager stateManager, GuiPreferences preferences) { + this.dialogService = dialogService; + this.stateManager = stateManager; + this.preferences = preferences; + + this.externalLinkCreator = new ExternalLinkCreator(preferences.getImporterPreferences()); + + BooleanExpression fieldIsSet = ActionHelper.isFieldSetForSelectedEntry(StandardField.TITLE, stateManager); + this.executable.bind(ActionHelper.needsEntriesSelected(1, stateManager).and(fieldIsSet)); + } + + @Override + public void execute() { + stateManager.getActiveDatabase().ifPresent(databaseContext -> { + final List bibEntries = stateManager.getSelectedEntries(); + externalLinkCreator.getSemanticScholarSearchURL(bibEntries.getFirst()).ifPresent(url -> { + try { + NativeDesktop.openExternalViewer(databaseContext, preferences, url, StandardField.URL, dialogService, bibEntries.getFirst()); + } catch (IOException ex) { + LOGGER.warn("Could not open Semantic Scholar", ex); + dialogService.notify(Localization.lang("Unable to open Semantic Scholar.") + " " + ex.getMessage()); + } + }); + }); + } +} diff --git a/jabgui/src/main/java/org/jabref/gui/maintable/SearchShortScienceAction.java b/jabgui/src/main/java/org/jabref/gui/maintable/SearchShortScienceAction.java index 4b6a251c4ff..05aee522bd0 100644 --- a/jabgui/src/main/java/org/jabref/gui/maintable/SearchShortScienceAction.java +++ b/jabgui/src/main/java/org/jabref/gui/maintable/SearchShortScienceAction.java @@ -15,18 +15,25 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static org.jabref.gui.actions.ActionHelper.isFieldSetForSelectedEntry; import static org.jabref.gui.actions.ActionHelper.needsEntriesSelected; public class SearchShortScienceAction extends SimpleCommand { + private static final Logger LOGGER = LoggerFactory.getLogger(SearchShortScienceAction.class); + private final DialogService dialogService; private final StateManager stateManager; private final GuiPreferences preferences; + private final ExternalLinkCreator externalLinkCreator; public SearchShortScienceAction(DialogService dialogService, StateManager stateManager, GuiPreferences preferences) { this.dialogService = dialogService; this.stateManager = stateManager; this.preferences = preferences; + this.externalLinkCreator = new ExternalLinkCreator(preferences.getImporterPreferences()); BooleanExpression fieldIsSet = isFieldSetForSelectedEntry(StandardField.TITLE, stateManager); this.executable.bind(needsEntriesSelected(1, stateManager).and(fieldIsSet)); @@ -41,11 +48,12 @@ public void execute() { dialogService.notify(Localization.lang("This operation requires exactly one item to be selected.")); return; } - ExternalLinkCreator.getShortScienceSearchURL(bibEntries.getFirst()).ifPresent(url -> { + externalLinkCreator.getShortScienceSearchURL(bibEntries.getFirst()).ifPresent(url -> { try { NativeDesktop.openExternalViewer(databaseContext, preferences, url, StandardField.URL, dialogService, bibEntries.getFirst()); } catch (IOException ex) { - dialogService.showErrorDialogAndWait(Localization.lang("Unable to open ShortScience."), ex); + LOGGER.warn("Could not open ShortScience", ex); + dialogService.notify(Localization.lang("Unable to open ShortScience.") + " " + ex.getMessage()); } }); }); diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/SearchEngineItem.java b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/SearchEngineItem.java new file mode 100644 index 00000000000..c10d3f79f0b --- /dev/null +++ b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/SearchEngineItem.java @@ -0,0 +1,34 @@ +package org.jabref.gui.preferences.websearch; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +public class SearchEngineItem { + private final StringProperty name; + private final StringProperty urlTemplate; + + public SearchEngineItem(String name, String urlTemplate) { + this.name = new SimpleStringProperty(name); + this.urlTemplate = new SimpleStringProperty(urlTemplate); + } + + public StringProperty nameProperty() { + return name; + } + + public StringProperty urlTemplateProperty() { + return urlTemplate; + } + + public String getName() { + return name.get(); + } + + public String getUrlTemplate() { + return urlTemplate.get(); + } + + public void setUrlTemplate(String urlTemplate) { + this.urlTemplate.set(urlTemplate); + } +} diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java index 2ff5b80a836..f8a65396df0 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.java @@ -12,7 +12,10 @@ import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; import javafx.scene.control.TextField; +import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; @@ -45,6 +48,10 @@ public class WebSearchTab extends AbstractPreferenceTabView searchEngineTable; + @FXML private TableColumn searchEngineName; + @FXML private TableColumn searchEngineUrlTemplate; + @FXML private VBox fetchersContainer; private final ReadOnlyBooleanProperty refAiEnabled; @@ -77,6 +84,16 @@ public String getTabName() { public void initialize() { this.viewModel = new WebSearchTabViewModel(preferences, refAiEnabled, taskExecutor); + searchEngineName.setCellValueFactory(param -> param.getValue().nameProperty()); + searchEngineName.setCellFactory(TextFieldTableCell.forTableColumn()); + searchEngineName.setEditable(false); + + searchEngineUrlTemplate.setCellValueFactory(param -> param.getValue().urlTemplateProperty()); + searchEngineUrlTemplate.setCellFactory(TextFieldTableCell.forTableColumn()); + searchEngineUrlTemplate.setEditable(true); + + searchEngineTable.setItems(viewModel.getSearchEngines()); + enableWebSearch.selectedProperty().bindBidirectional(viewModel.enableWebSearchProperty()); warnAboutDuplicatesOnImport.selectedProperty().bindBidirectional(viewModel.warnAboutDuplicatesOnImportProperty()); downloadLinkedOnlineFiles.selectedProperty().bindBidirectional(viewModel.shouldDownloadLinkedOnlineFiles()); diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java index ac4e5ddd7af..e2897943b4b 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTabViewModel.java @@ -5,6 +5,7 @@ import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.function.Consumer; @@ -51,7 +52,7 @@ public class WebSearchTabViewModel implements PreferenceTabViewModel { private final BooleanProperty enableWebSearchProperty = new SimpleBooleanProperty(); private final BooleanProperty warnAboutDuplicatesOnImportProperty = new SimpleBooleanProperty(); private final BooleanProperty shouldDownloadLinkedOnlineFiles = new SimpleBooleanProperty(); - private final BooleanProperty shouldkeepDownloadUrl = new SimpleBooleanProperty(); + private final BooleanProperty shouldKeepDownloadUrl = new SimpleBooleanProperty(); private final ListProperty plainCitationParsers = new SimpleListProperty<>(FXCollections.observableArrayList(PlainCitationParserChoice.values())); @@ -72,7 +73,8 @@ public class WebSearchTabViewModel implements PreferenceTabViewModel { private final BooleanProperty apikeyPersistProperty = new SimpleBooleanProperty(); private final BooleanProperty apikeyPersistAvailableProperty = new SimpleBooleanProperty(); - private final CliPreferences preferences; + private final ObservableList searchEngines = FXCollections.observableArrayList(); + private final DOIPreferences doiPreferences; private final GrobidPreferences grobidPreferences; private final ImporterPreferences importerPreferences; @@ -84,7 +86,6 @@ public class WebSearchTabViewModel implements PreferenceTabViewModel { private final ReadOnlyBooleanProperty refAiEnabled; public WebSearchTabViewModel(CliPreferences preferences, ReadOnlyBooleanProperty refAiEnabled, TaskExecutor taskExecutor) { - this.preferences = preferences; this.importerPreferences = preferences.getImporterPreferences(); this.grobidPreferences = preferences.getGrobidPreferences(); this.doiPreferences = preferences.getDOIPreferences(); @@ -95,15 +96,16 @@ public WebSearchTabViewModel(CliPreferences preferences, ReadOnlyBooleanProperty this.refAiEnabled = refAiEnabled; - setupPlainCitationParsers(preferences); + setupPlainCitationParsers(); + setupSearchEngines(); } - private void setupPlainCitationParsers(CliPreferences preferences) { + private void setupPlainCitationParsers() { if (!refAiEnabled.get()) { plainCitationParsers.remove(PlainCitationParserChoice.LLM); } - refAiEnabled.addListener((observable, oldValue, newValue) -> { + refAiEnabled.addListener((_, _, newValue) -> { if (newValue) { plainCitationParsers.add(PlainCitationParserChoice.LLM); } else { @@ -121,7 +123,7 @@ private void setupPlainCitationParsers(CliPreferences preferences) { plainCitationParsers.remove(PlainCitationParserChoice.GROBID); } - grobidEnabledProperty.addListener((observable, oldValue, newValue) -> { + grobidEnabledProperty.addListener((_, _, newValue) -> { if (newValue) { plainCitationParsers.add(PlainCitationParserChoice.GROBID); } else { @@ -136,12 +138,21 @@ private void setupPlainCitationParsers(CliPreferences preferences) { }); } + private void setupSearchEngines() { + // add default search engines + searchEngines.addAll( + new SearchEngineItem("Google Scholar", "https://scholar.google.com/scholar?q={title}"), + new SearchEngineItem("Semantic Scholar", "https://www.semanticscholar.org/search?q={title}"), + new SearchEngineItem("Short Science", "https://www.shortscience.org/internalsearch?q={title}") + ); + } + @Override public void setValues() { enableWebSearchProperty.setValue(importerPreferences.areImporterEnabled()); warnAboutDuplicatesOnImportProperty.setValue(importerPreferences.shouldWarnAboutDuplicatesOnImport()); shouldDownloadLinkedOnlineFiles.setValue(filePreferences.shouldDownloadLinkedFiles()); - shouldkeepDownloadUrl.setValue(filePreferences.shouldKeepDownloadUrl()); + shouldKeepDownloadUrl.setValue(filePreferences.shouldKeepDownloadUrl()); addImportedEntries.setValue(libraryPreferences.isAddImportedEntriesEnabled()); addImportedEntriesGroupName.setValue(libraryPreferences.getAddImportedEntriesGroupName()); defaultPlainCitationParser.setValue(importerPreferences.getDefaultPlainCitationParser()); @@ -153,7 +164,7 @@ public void setValues() { grobidEnabledProperty.setValue(grobidPreferences.isGrobidEnabled()); grobidURLProperty.setValue(grobidPreferences.getGrobidURL()); - Set savedApiKeys = preferences.getImporterPreferences().getApiKeys(); + Set savedApiKeys = importerPreferences.getApiKeys(); Set enabledCatalogs = new HashSet<>(importerPreferences.getCatalogs()); List allFetchers = WebFetchers.getSearchBasedFetchers(importFormatPreferences, importerPreferences) @@ -185,7 +196,14 @@ public void setValues() { } apikeyPersistAvailableProperty.setValue(OS.isKeyringAvailable()); - apikeyPersistProperty.setValue(preferences.getImporterPreferences().shouldPersistCustomKeys()); + apikeyPersistProperty.setValue(importerPreferences.shouldPersistCustomKeys()); + + // Load custom URL templates from preferences if they exist + Map savedTemplates = importerPreferences.getSearchEngineUrlTemplates(); + if (!savedTemplates.isEmpty()) { + searchEngines.clear(); + savedTemplates.forEach((name, url) -> searchEngines.add(new SearchEngineItem(name, url))); + } } @Override @@ -193,7 +211,7 @@ public void storeSettings() { importerPreferences.setImporterEnabled(enableWebSearchProperty.getValue()); importerPreferences.setWarnAboutDuplicatesOnImport(warnAboutDuplicatesOnImportProperty.getValue()); filePreferences.setDownloadLinkedFiles(shouldDownloadLinkedOnlineFiles.getValue()); - filePreferences.setKeepDownloadUrl(shouldkeepDownloadUrl.getValue()); + filePreferences.setKeepDownloadUrl(shouldKeepDownloadUrl.getValue()); libraryPreferences.setAddImportedEntries(addImportedEntries.getValue()); if (addImportedEntriesGroupName.getValue().isEmpty() || addImportedEntriesGroupName.getValue().startsWith(" ")) { libraryPreferences.setAddImportedEntriesGroupName(Localization.lang("Imported entries")); @@ -221,10 +239,18 @@ public void storeSettings() { .toList(); importerPreferences.setPersistCustomKeys(apikeyPersistProperty.get()); - preferences.getImporterPreferences().getApiKeys().clear(); + importerPreferences.getApiKeys().clear(); if (apikeyPersistAvailableProperty.get()) { - preferences.getImporterPreferences().getApiKeys().addAll(apiKeysToStore); + importerPreferences.getApiKeys().addAll(apiKeysToStore); } + + // Save custom URL templates to preferences + Map templates = searchEngines.stream() + .collect(Collectors.toMap( + SearchEngineItem::getName, + SearchEngineItem::getUrlTemplate + )); + importerPreferences.setSearchEngineUrlTemplates(templates); } public BooleanProperty enableWebSearchProperty() { @@ -276,7 +302,7 @@ public BooleanProperty shouldDownloadLinkedOnlineFiles() { } public BooleanProperty shouldKeepDownloadUrl() { - return shouldkeepDownloadUrl; + return shouldKeepDownloadUrl; } public ReadOnlyBooleanProperty apiKeyPersistAvailable() { @@ -291,6 +317,10 @@ public IntegerProperty citationsRelationsStoreTTLProperty() { return citationsRelationStoreTTL; } + public ObservableList getSearchEngines() { + return searchEngines; + } + public void checkApiKey(FetcherViewModel fetcherViewModel, String apiKey, Consumer onFinished) { Callable tester = () -> { WebFetcher webFetcher = fetcherViewModel.getFetcher(); diff --git a/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml b/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml index cf9d45183de..16e24877297 100644 --- a/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml +++ b/jabgui/src/main/resources/org/jabref/gui/preferences/websearch/WebSearchTab.fxml @@ -3,6 +3,8 @@ + + @@ -47,6 +49,28 @@ +