suggestions = suggestionProvider
+ .getPossibleSuggestions()
+ .stream()
+ .map(suggestion -> suggestion instanceof BibEntry bibEntry ? bibEntry.getCitationKey().orElse("") : (String) suggestion)
+ .filter(suggestion -> suggestion.toLowerCase(Locale.ROOT).contains(request.toLowerCase(Locale.ROOT)))
+ .map(suggestion -> new ParsedEntryLink(suggestion, databaseContext.getDatabase()))
+ .distinct()
+ .collect(Collectors.toList());
+
+ ParsedEntryLink requestedLink = new ParsedEntryLink(request, databaseContext.getDatabase());
+ if (!suggestions.contains(requestedLink)) {
+ suggestions.addFirst(requestedLink);
+ }
+
+ return suggestions;
+ }
+
public void jumpToEntry(ParsedEntryLink parsedEntryLink) {
- // TODO: Implement jump to entry - The implementation can be based on JabRefFrame.jumpToEntry
- // TODO: Add toolitp for tag: Localization.lang("Jump to entry")
- // This feature was removed while converting the linked entries editor to JavaFX
- // Right now there is no nice way to re-implement it as we have no good interface to control the focus of the main table
- // (except directly using the JabRefFrame class as below)
- // parsedEntryLink.getLinkedEntry().ifPresent(
- // e -> frame.getCurrentBasePanel().highlightEntry(e)
- // );
+ parsedEntryLink.getLinkedEntry().ifPresent(entry ->
+ stateManager.activeTabProperty().get().ifPresent(tab -> tab.clearAndSelect(entry)));
}
}
diff --git a/src/main/java/org/jabref/gui/icon/IconTheme.java b/src/main/java/org/jabref/gui/icon/IconTheme.java
index 10be9e16090..cc9bad0528b 100644
--- a/src/main/java/org/jabref/gui/icon/IconTheme.java
+++ b/src/main/java/org/jabref/gui/icon/IconTheme.java
@@ -193,6 +193,7 @@ public enum JabRefIcons implements JabRefIcon {
DELETE_ENTRY(MaterialDesignD.DELETE),
SEARCH(MaterialDesignM.MAGNIFY),
FILE_SEARCH(MaterialDesignF.FILE_FIND),
+ FILE_STAR(MaterialDesignF.FILE_STAR),
PDF_METADATA_READ(MaterialDesignF.FORMAT_ALIGN_TOP),
PDF_METADATA_WRITE(MaterialDesignF.FORMAT_ALIGN_BOTTOM),
ADVANCED_SEARCH(Color.CYAN, MaterialDesignM.MAGNIFY),
@@ -278,6 +279,7 @@ public enum JabRefIcons implements JabRefIcon {
APPLICATION_WINEDT(JabRefMaterialDesignIcon.WINEDT),
APPLICATION_SUBLIMETEXT(JabRefMaterialDesignIcon.SUBLIME_TEXT),
APPLICATION_TEXSHOP(JabRefMaterialDesignIcon.TEXSHOP),
+ APPLICATION_TEXWORS(JabRefMaterialDesignIcon.TEXWORKS),
KEY_BINDINGS(MaterialDesignK.KEYBOARD),
FIND_DUPLICATES(MaterialDesignC.CODE_EQUAL),
CONNECT_DB(MaterialDesignC.CLOUD_UPLOAD),
diff --git a/src/main/java/org/jabref/gui/icon/JabRefMaterialDesignIcon.java b/src/main/java/org/jabref/gui/icon/JabRefMaterialDesignIcon.java
index 6f697cc1e4a..5d8deaa5d91 100644
--- a/src/main/java/org/jabref/gui/icon/JabRefMaterialDesignIcon.java
+++ b/src/main/java/org/jabref/gui/icon/JabRefMaterialDesignIcon.java
@@ -5,7 +5,7 @@
/**
* Provides the same true-type font interface as MaterialDesignIcon itself, but uses a font we created ourselves that
* contains icons that are not available in MaterialDesignIcons.
- *
+ *
* The glyphs of the ttf (speak: the icons) were created with Illustrator and a template from the material design icons
* web-page. The art boards for each icon was exported as SVG and then converted with
* IcoMoon. The final TTF font is located in the resource folder.
@@ -31,7 +31,8 @@ public enum JabRefMaterialDesignIcon implements Ikon {
VSCODE("jab-vsvode", '\ue90d'),
CANCEL("jab-cancel", '\ue90e'),
SUBLIME_TEXT("jab-sublime-text", '\ue90f'),
- TEXSHOP("jab-texshop", '\ue910');
+ TEXSHOP("jab-texshop", '\ue910'),
+ TEXWORKS("jab-texworks", '\ue911');
private String description;
private int code;
diff --git a/src/main/java/org/jabref/gui/maintable/ExtractReferencesAction.java b/src/main/java/org/jabref/gui/maintable/ExtractReferencesAction.java
new file mode 100644
index 00000000000..d46854c5f55
--- /dev/null
+++ b/src/main/java/org/jabref/gui/maintable/ExtractReferencesAction.java
@@ -0,0 +1,101 @@
+package org.jabref.gui.maintable;
+
+import java.nio.file.Path;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+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.importer.ImportEntriesDialog;
+import org.jabref.gui.util.BackgroundTask;
+import org.jabref.gui.util.TaskExecutor;
+import org.jabref.logic.importer.ParserResult;
+import org.jabref.logic.importer.util.GrobidService;
+import org.jabref.logic.l10n.Localization;
+import org.jabref.logic.util.io.FileUtil;
+import org.jabref.model.entry.BibEntry;
+import org.jabref.model.entry.LinkedFile;
+import org.jabref.preferences.PreferencesService;
+
+public class ExtractReferencesAction extends SimpleCommand {
+ private final int FILES_LIMIT = 10;
+
+ private final DialogService dialogService;
+ private final StateManager stateManager;
+ private final PreferencesService preferencesService;
+ private final BibEntry entry;
+ private final LinkedFile linkedFile;
+ private final TaskExecutor taskExecutor;
+
+ public ExtractReferencesAction(DialogService dialogService,
+ StateManager stateManager,
+ PreferencesService preferencesService,
+ TaskExecutor taskExecutor) {
+ this(dialogService, stateManager, preferencesService, null, null, taskExecutor);
+ }
+
+ public ExtractReferencesAction(DialogService dialogService,
+ StateManager stateManager,
+ PreferencesService preferencesService,
+ BibEntry entry,
+ LinkedFile linkedFile,
+ TaskExecutor taskExecutor) {
+ this.dialogService = dialogService;
+ this.stateManager = stateManager;
+ this.preferencesService = preferencesService;
+ this.entry = entry;
+ this.linkedFile = linkedFile;
+ this.taskExecutor = taskExecutor;
+
+ if (this.linkedFile == null) {
+ this.executable.bind(
+ ActionHelper.needsEntriesSelected(stateManager)
+ .and(ActionHelper.hasLinkedFileForSelectedEntries(stateManager))
+ .and(this.preferencesService.getGrobidPreferences().grobidEnabledProperty())
+ );
+ } else {
+ this.setExecutable(true);
+ }
+ }
+
+ @Override
+ public void execute() {
+ extractReferences();
+ }
+
+ private void extractReferences() {
+ stateManager.getActiveDatabase().ifPresent(databaseContext -> {
+ List selectedEntries = new LinkedList<>();
+ if (entry == null) {
+ selectedEntries = stateManager.getSelectedEntries();
+ } else {
+ selectedEntries.add(entry);
+ }
+
+ List fileList = FileUtil.getListOfLinkedFiles(selectedEntries, databaseContext.getFileDirectories(preferencesService.getFilePreferences()));
+ if (fileList.size() > FILES_LIMIT) {
+ boolean continueOpening = dialogService.showConfirmationDialogAndWait(Localization.lang("Processing a large number of files"),
+ Localization.lang("You are about to process %0 files. Continue?", fileList.size()),
+ Localization.lang("Continue"), Localization.lang("Cancel"));
+ if (!continueOpening) {
+ return;
+ }
+ }
+
+ Callable parserResultCallable = () -> new ParserResult(
+ new GrobidService(this.preferencesService.getGrobidPreferences()).processReferences(fileList, preferencesService.getImportFormatPreferences())
+ );
+ BackgroundTask task = BackgroundTask.wrap(parserResultCallable)
+ .withInitialMessage(Localization.lang("Processing PDF(s)"));
+
+ task.onFailure(dialogService::showErrorDialogAndWait);
+
+ ImportEntriesDialog dialog = new ImportEntriesDialog(stateManager.getActiveDatabase().get(), task);
+ dialog.setTitle(Localization.lang("Extract References"));
+ dialogService.showCustomDialogAndWait(dialog);
+ });
+ }
+}
diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java
index 6e65da6ab13..aa8a5477902 100644
--- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java
+++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java
@@ -75,6 +75,7 @@ public static ContextMenu create(BibEntryTableViewModel entry,
factory.createMenuItem(StandardActions.ATTACH_FILE_FROM_URL, new AttachFileFromURLAction(dialogService, stateManager, taskExecutor, preferencesService)),
factory.createMenuItem(StandardActions.OPEN_FOLDER, new OpenFolderAction(dialogService, stateManager, preferencesService, taskExecutor)),
factory.createMenuItem(StandardActions.OPEN_EXTERNAL_FILE, new OpenExternalFileAction(dialogService, stateManager, preferencesService, taskExecutor)),
+ factory.createMenuItem(StandardActions.EXTRACT_FILE_REFERENCES, new ExtractReferencesAction(dialogService, stateManager, preferencesService, taskExecutor)),
factory.createMenuItem(StandardActions.OPEN_URL, new OpenUrlAction(dialogService, stateManager, preferencesService)),
factory.createMenuItem(StandardActions.SEARCH_SHORTSCIENCE, new SearchShortScienceAction(dialogService, stateManager, preferencesService)),
diff --git a/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTab.fxml b/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTab.fxml
index d4f96a6178c..09ac50e21ee 100644
--- a/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTab.fxml
+++ b/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTab.fxml
@@ -4,10 +4,10 @@
-
+
@@ -22,11 +22,11 @@
-
+
-
+
implements PreferencesTab {
@FXML private CheckBox enableAutoComplete;
- @FXML private TextField autoCompleteFields;
+ @FXML private TagsField autoCompleteFields;
@FXML private RadioButton autoCompleteFirstLast;
@FXML private RadioButton autoCompleteLastFirst;
@FXML private RadioButton autoCompleteBoth;
@@ -35,9 +41,8 @@ public String getTabName() {
public void initialize() {
viewModel = new AutoCompletionTabViewModel(preferencesService.getAutoCompletePreferences());
-
+ setupTagsFiled();
enableAutoComplete.selectedProperty().bindBidirectional(viewModel.enableAutoCompleteProperty());
- autoCompleteFields.textProperty().bindBidirectional(viewModel.autoCompleteFieldsProperty());
autoCompleteFirstLast.selectedProperty().bindBidirectional(viewModel.autoCompleteFirstLastProperty());
autoCompleteLastFirst.selectedProperty().bindBidirectional(viewModel.autoCompleteLastFirstProperty());
autoCompleteBoth.selectedProperty().bindBidirectional(viewModel.autoCompleteBothProperty());
@@ -45,4 +50,24 @@ public void initialize() {
firstNameModeFull.selectedProperty().bindBidirectional(viewModel.firstNameModeFullProperty());
firstNameModeBoth.selectedProperty().bindBidirectional(viewModel.firstNameModeBothProperty());
}
+
+ private void setupTagsFiled() {
+ autoCompleteFields.setCellFactory(new ViewModelListCellFactory().withText(Field::getDisplayName));
+ autoCompleteFields.setSuggestionProvider(request -> viewModel.getSuggestions(request.getUserText()));
+ autoCompleteFields.tagsProperty().bindBidirectional(viewModel.autoCompleteFieldsProperty());
+ autoCompleteFields.setConverter(viewModel.getFieldStringConverter());
+ autoCompleteFields.setTagViewFactory(this::createTag);
+ autoCompleteFields.setShowSearchIcon(false);
+ autoCompleteFields.getEditor().getStyleClass().clear();
+ autoCompleteFields.getEditor().getStyleClass().add("tags-field-editor");
+ }
+
+ private Node createTag(Field field) {
+ Label tagLabel = new Label();
+ tagLabel.setText(field.getDisplayName());
+ tagLabel.setGraphic(IconTheme.JabRefIcons.REMOVE_TAGS.getGraphicNode());
+ tagLabel.getGraphic().setOnMouseClicked(event -> autoCompleteFields.removeTags(field));
+ tagLabel.setContentDisplay(ContentDisplay.RIGHT);
+ return tagLabel;
+ }
}
diff --git a/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTabViewModel.java b/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTabViewModel.java
index 8b9b6633f6e..52b5c77bd7d 100644
--- a/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTabViewModel.java
+++ b/src/main/java/org/jabref/gui/preferences/autocompletion/AutoCompletionTabViewModel.java
@@ -2,22 +2,26 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleBooleanProperty;
-import javafx.beans.property.SimpleStringProperty;
-import javafx.beans.property.StringProperty;
+import javafx.beans.property.SimpleListProperty;
+import javafx.collections.FXCollections;
+import javafx.util.StringConverter;
import org.jabref.gui.autocompleter.AutoCompleteFirstNameMode;
import org.jabref.gui.autocompleter.AutoCompletePreferences;
import org.jabref.gui.preferences.PreferenceTabViewModel;
import org.jabref.logic.l10n.Localization;
+import org.jabref.model.entry.field.Field;
import org.jabref.model.entry.field.FieldFactory;
public class AutoCompletionTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty enableAutoCompleteProperty = new SimpleBooleanProperty();
- private final StringProperty autoCompleteFieldsProperty = new SimpleStringProperty();
+ private final ListProperty autoCompleteFieldsProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
private final BooleanProperty autoCompleteFirstLastProperty = new SimpleBooleanProperty();
private final BooleanProperty autoCompleteLastFirstProperty = new SimpleBooleanProperty();
private final BooleanProperty autoCompleteBothProperty = new SimpleBooleanProperty();
@@ -36,8 +40,7 @@ public AutoCompletionTabViewModel(AutoCompletePreferences autoCompletePreference
@Override
public void setValues() {
enableAutoCompleteProperty.setValue(autoCompletePreferences.shouldAutoComplete());
- autoCompleteFieldsProperty.setValue(autoCompletePreferences.getCompleteNamesAsString());
-
+ autoCompleteFieldsProperty.setValue(FXCollections.observableArrayList(autoCompletePreferences.getCompleteFields()));
if (autoCompletePreferences.getNameFormat() == AutoCompletePreferences.NameFormat.FIRST_LAST) {
autoCompleteFirstLastProperty.setValue(true);
} else if (autoCompletePreferences.getNameFormat() == AutoCompletePreferences.NameFormat.LAST_FIRST) {
@@ -82,7 +85,7 @@ public void storeSettings() {
}
autoCompletePreferences.getCompleteFields().clear();
- autoCompletePreferences.getCompleteFields().addAll(FieldFactory.parseFieldList(autoCompleteFieldsProperty.getValue()));
+ autoCompletePreferences.getCompleteFields().addAll(autoCompleteFieldsProperty.getValue());
}
@Override
@@ -94,7 +97,7 @@ public BooleanProperty enableAutoCompleteProperty() {
return enableAutoCompleteProperty;
}
- public StringProperty autoCompleteFieldsProperty() {
+ public ListProperty autoCompleteFieldsProperty() {
return autoCompleteFieldsProperty;
}
@@ -121,4 +124,24 @@ public BooleanProperty firstNameModeFullProperty() {
public BooleanProperty firstNameModeBothProperty() {
return firstNameModeBothProperty;
}
+
+ public StringConverter getFieldStringConverter() {
+ return new StringConverter<>() {
+ @Override
+ public String toString(Field field) {
+ return field.getDisplayName();
+ }
+
+ @Override
+ public Field fromString(String string) {
+ return FieldFactory.parseField(string);
+ }
+ };
+ }
+
+ public List getSuggestions(String request) {
+ return FieldFactory.getAllFieldsWithOutInternal().stream()
+ .filter(field -> field.getDisplayName().toLowerCase().contains(request.toLowerCase()))
+ .collect(Collectors.toList());
+ }
}
diff --git a/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.fxml b/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.fxml
index 06ee5a0e0dd..57cd5a4a449 100644
--- a/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.fxml
+++ b/src/main/java/org/jabref/gui/preferences/websearch/WebSearchTab.fxml
@@ -2,7 +2,6 @@
-
@@ -55,12 +54,29 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+