Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
315 changes: 217 additions & 98 deletions CHANGELOG.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public enum StandardActions implements Action {
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_SHORTSCIENCE(Localization.lang("Search ShortScience")),
SEARCH_GOOGLE_SCHOLAR(Localization.lang("Search Google Scholar")),
SEARCH(Localization.lang("Search...")),
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/...")),
ATTACH_FILE(Localization.lang("Attach file"), IconTheme.JabRefIcons.ATTACH_FILE),
Expand Down
3 changes: 2 additions & 1 deletion jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ public MainTable(MainTableDataModel model,
taskExecutor,
Injector.instantiateModelOrService(JournalAbbreviationRepository.class),
entryTypesManager,
importHandler))
importHandler,
preferences.getImporterPreferences()))
.withPseudoClass(MATCHING_SEARCH_AND_GROUPS, entry -> entry.matchCategory().isEqualTo(MatchCategory.MATCHING_SEARCH_AND_GROUPS))
.withPseudoClass(MATCHING_SEARCH_NOT_GROUPS, entry -> entry.matchCategory().isEqualTo(MatchCategory.MATCHING_SEARCH_NOT_GROUPS))
.withPseudoClass(MATCHING_GROUPS_NOT_SEARCH, entry -> entry.matchCategory().isEqualTo(MatchCategory.MATCHING_GROUPS_NOT_SEARCH))
Expand Down
20 changes: 17 additions & 3 deletions jabgui/src/main/java/org/jabref/gui/maintable/RightClickMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory;
import org.jabref.logic.citationstyle.CitationStyleOutputFormat;
import org.jabref.logic.citationstyle.CitationStylePreviewLayout;
import org.jabref.logic.importer.ImporterPreferences;
import org.jabref.logic.importer.WebFetchers;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.l10n.Localization;
Expand All @@ -62,7 +63,8 @@ public static ContextMenu create(BibEntryTableViewModel entry,
TaskExecutor taskExecutor,
JournalAbbreviationRepository abbreviationRepository,
BibEntryTypesManager entryTypesManager,
ImportHandler importHandler) {
ImportHandler importHandler,
ImporterPreferences importerPreferences) {
ActionFactory factory = new ActionFactory();
ContextMenu contextMenu = new ContextMenu();

Expand Down Expand Up @@ -101,8 +103,7 @@ 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, importerPreferences),
new SeparatorMenuItem(),

new ChangeEntryTypeMenu(libraryTab.getSelectedEntries(), libraryTab.getBibDatabaseContext(), undoManager, entryTypesManager).asSubMenu(),
Expand Down Expand Up @@ -219,4 +220,17 @@ private static Menu createSendSubMenu(ActionFactory factory,

return sendMenu;
}

private static Menu createSearchSubMenu(ActionFactory factory,
DialogService dialogService,
StateManager stateManager,
GuiPreferences preferences,
ImporterPreferences importerPreferences) {
Menu searchMenu = factory.createMenu(StandardActions.SEARCH);
searchMenu.getItems().addAll(
factory.createMenuItem(StandardActions.SEARCH_SHORTSCIENCE, new SearchShortScienceAction(dialogService, stateManager, preferences, importerPreferences)),
factory.createMenuItem(StandardActions.SEARCH_GOOGLE_SCHOLAR, new SearchGoogleScholarAction(dialogService, stateManager, preferences, importerPreferences))
);
return searchMenu;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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.importer.ImporterPreferences;
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 static org.jabref.gui.actions.ActionHelper.isFieldSetForSelectedEntry;
import static org.jabref.gui.actions.ActionHelper.needsEntriesSelected;

public class SearchGoogleScholarAction extends SimpleCommand {
private final DialogService dialogService;
private final StateManager stateManager;
private final GuiPreferences preferences;
private final ExternalLinkCreator externalLinkCreator;

public SearchGoogleScholarAction(DialogService dialogService, StateManager stateManager, GuiPreferences preferences, ImporterPreferences importerPreferences) {
this.dialogService = dialogService;
this.stateManager = stateManager;
this.preferences = preferences;
this.externalLinkCreator = new ExternalLinkCreator(importerPreferences);

BooleanExpression fieldIsSet = isFieldSetForSelectedEntry(StandardField.TITLE, stateManager);
this.executable.bind(needsEntriesSelected(1, stateManager).and(fieldIsSet));
}

@Override
public void execute() {
stateManager.getActiveDatabase().ifPresent(databaseContext -> {
final List<BibEntry> bibEntries = stateManager.getSelectedEntries();
externalLinkCreator.getGoogleScholarSearchURL(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 Google Scholar."), ex);
}
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.desktop.os.NativeDesktop;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.logic.importer.ImporterPreferences;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.util.ExternalLinkCreator;
import org.jabref.model.entry.BibEntry;
Expand All @@ -22,11 +23,13 @@ public class SearchShortScienceAction extends SimpleCommand {
private final DialogService dialogService;
private final StateManager stateManager;
private final GuiPreferences preferences;
private final ExternalLinkCreator externalLinkCreator;

public SearchShortScienceAction(DialogService dialogService, StateManager stateManager, GuiPreferences preferences) {
public SearchShortScienceAction(DialogService dialogService, StateManager stateManager, GuiPreferences preferences, ImporterPreferences importerPreferences) {
this.dialogService = dialogService;
this.stateManager = stateManager;
this.preferences = preferences;
this.externalLinkCreator = new ExternalLinkCreator(importerPreferences);

BooleanExpression fieldIsSet = isFieldSetForSelectedEntry(StandardField.TITLE, stateManager);
this.executable.bind(needsEntriesSelected(1, stateManager).and(fieldIsSet));
Expand All @@ -41,7 +44,7 @@ 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public class WebSearchTab extends AbstractPreferenceTabView<WebSearchTabViewMode
@FXML private CheckBox grobidEnabled;
@FXML private TextField grobidURL;

@FXML private TableView<SearchEngineItem> searchEngineTable;
@FXML private TableColumn<SearchEngineItem, String> searchEngineName;
@FXML private TableColumn<SearchEngineItem, String> searchEngineUrlTemplate;

@FXML private TableView<FetcherApiKey> apiKeySelectorTable;
@FXML private TableColumn<FetcherApiKey, String> apiKeyName;
@FXML private TableColumn<FetcherApiKey, String> customApiKey;
Expand Down Expand Up @@ -75,6 +79,16 @@ public String getTabName() {
public void initialize() {
this.viewModel = new WebSearchTabViewModel(preferences, dialogService, refAiEnabled);

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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -68,6 +69,8 @@ public class WebSearchTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty apikeyPersistProperty = new SimpleBooleanProperty();
private final BooleanProperty apikeyPersistAvailableProperty = new SimpleBooleanProperty();

private final ObservableList<SearchEngineItem> searchEngines = FXCollections.observableArrayList();

private final DialogService dialogService;
private final CliPreferences preferences;
private final DOIPreferences doiPreferences;
Expand All @@ -92,6 +95,7 @@ public WebSearchTabViewModel(CliPreferences preferences, DialogService dialogSer
this.refAiEnabled = refAiEnabled;

setupPlainCitationParsers(preferences);
setupSearchEngines();
}

private void setupPlainCitationParsers(CliPreferences preferences) {
Expand Down Expand Up @@ -132,6 +136,14 @@ 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("Short Science", "https://www.shortscience.org/internalsearch?q={title}")
);
}

@Override
public void setValues() {
enableWebSearchProperty.setValue(importerPreferences.areImporterEnabled());
Expand Down Expand Up @@ -164,6 +176,13 @@ public void setValues() {
return new StudyCatalogItem(name, enabled);
})
.toList());

// Load custom URL templates from preferences if they exist
Map<String, String> savedTemplates = preferences.getImporterPreferences().getSearchEngineUrlTemplates();
if (!savedTemplates.isEmpty()) {
searchEngines.clear();
savedTemplates.forEach((name, url) -> searchEngines.add(new SearchEngineItem(name, url)));
}
}

@Override
Expand Down Expand Up @@ -196,6 +215,14 @@ public void storeSettings() {
if (apikeyPersistAvailableProperty.get()) {
preferences.getImporterPreferences().getApiKeys().addAll(apiKeys);
}

// Save custom URL templates to preferences
Map<String, String> templates = searchEngines.stream()
.collect(Collectors.toMap(
SearchEngineItem::getName,
SearchEngineItem::getUrlTemplate
));
preferences.getImporterPreferences().setSearchEngineUrlTemplates(templates);
}

public BooleanProperty enableWebSearchProperty() {
Expand Down Expand Up @@ -270,6 +297,10 @@ public IntegerProperty citationsRelationsStoreTTLProperty() {
return citationsRelationStoreTTL;
}

public ObservableList<SearchEngineItem> getSearchEngines() {
return searchEngines;
}

public void checkCustomApiKey() {
final String apiKeyName = selectedApiKeyProperty.get().getName();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.ComboBox?>
<?import org.jabref.gui.preferences.websearch.SearchEngineItem?>

<fx:root spacing="10.0" type="VBox"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="org.jabref.gui.preferences.websearch.WebSearchTab">
Expand Down Expand Up @@ -66,6 +68,28 @@
<TextField fx:id="grobidURL" HBox.hgrow="ALWAYS"/>
</HBox>

<Label styleClass="sectionHeader" text="%Search Engine URL Templates"/>
<Label text="%( Note: Press return to commit changes in the table! )"/>
<TableView
fx:id="searchEngineTable"
VBox.vgrow="ALWAYS"
editable="true">
<columns>
<TableColumn minWidth="120"
fx:id="searchEngineName"
text="%Search Engine"
editable="false"/>
<TableColumn minWidth="300"
fx:id="searchEngineUrlTemplate"
text="%URL Template"
editable="true"/>
</columns>
<columnResizePolicy>
<TableView
fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>

<Label styleClass="sectionHeader" text="%Custom API key"/>
<Label text="%( Note: Press return to commit changes in the table! )"/>
<TableView
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jabref.logic.importer;

import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -32,6 +33,7 @@ public class ImporterPreferences {
private final ObservableList<String> catalogs;
private final ObjectProperty<PlainCitationParserChoice> defaultPlainCitationParser;
private final IntegerProperty citationsRelationsStoreTTL;
private final Map<String, String> searchEngineUrlTemplates;

public ImporterPreferences(boolean importerEnabled,
boolean generateNewKeyOnImport,
Expand All @@ -43,7 +45,8 @@ public ImporterPreferences(boolean importerEnabled,
boolean persistCustomKeys,
List<String> catalogs,
PlainCitationParserChoice defaultPlainCitationParser,
int citationsRelationsStoreTTL
int citationsRelationsStoreTTL,
Map<String, String> searchEngineUrlTemplates
) {
this.importerEnabled = new SimpleBooleanProperty(importerEnabled);
this.generateNewKeyOnImport = new SimpleBooleanProperty(generateNewKeyOnImport);
Expand All @@ -56,6 +59,7 @@ public ImporterPreferences(boolean importerEnabled,
this.catalogs = FXCollections.observableArrayList(catalogs);
this.defaultPlainCitationParser = new SimpleObjectProperty<>(defaultPlainCitationParser);
this.citationsRelationsStoreTTL = new SimpleIntegerProperty(citationsRelationsStoreTTL);
this.searchEngineUrlTemplates = new HashMap<>(searchEngineUrlTemplates);
}

public boolean areImporterEnabled() {
Expand Down Expand Up @@ -150,7 +154,7 @@ public void setCatalogs(List<String> catalogs) {
}

public ObservableList<String> getCatalogs() {
return catalogs;
return catalogs;
}

public PlainCitationParserChoice getDefaultPlainCitationParser() {
Expand All @@ -176,4 +180,13 @@ public IntegerProperty citationsRelationsStoreTTLProperty() {
public void setCitationsRelationsStoreTTL(int citationsRelationsStoreTTL) {
this.citationsRelationsStoreTTL.set(citationsRelationsStoreTTL);
}

public Map<String, String> getSearchEngineUrlTemplates() {
return searchEngineUrlTemplates;
}

public void setSearchEngineUrlTemplates(Map<String, String> templates) {
searchEngineUrlTemplates.clear();
searchEngineUrlTemplates.putAll(templates);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2077,7 +2077,8 @@ public ImporterPreferences getImporterPreferences() {
getBoolean(FETCHER_CUSTOM_KEY_PERSIST),
getStringList(SEARCH_CATALOGS),
PlainCitationParserChoice.valueOf(get(DEFAULT_PLAIN_CITATION_PARSER)),
getInt(CITATIONS_RELATIONS_STORE_TTL)
getInt(CITATIONS_RELATIONS_STORE_TTL),
Map.of()
);

EasyBind.listen(importerPreferences.importerEnabledProperty(), (_, _, newValue) -> putBoolean(IMPORTERS_ENABLED, newValue));
Expand Down
Loading
Loading