Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
b4f1af6
Extract text about papers from "related work" sections
pluto-han Mar 11, 2026
0f5e61f
Update comments
pluto-han Mar 11, 2026
a39f109
small refactor
pluto-han Mar 11, 2026
b29e400
Merge remote-tracking branch 'origin/fix-for-issue-14085' into fix-fo…
pluto-han Mar 11, 2026
08df1f3
small refactor of comments
pluto-han Mar 12, 2026
2e16150
Merge branch 'main' into fix-for-issue-14085
pluto-han Mar 12, 2026
960a263
Support more citation format
pluto-han Mar 12, 2026
89c8f94
Merge branch 'main' into fix-for-issue-14085
pluto-han Mar 12, 2026
b9cc731
Modify logic for UI
pluto-han Mar 14, 2026
a294b9e
Add UI
pluto-han Mar 14, 2026
dd186e1
make `RelatedWorkAction` inline
pluto-han Mar 16, 2026
8e7c5d1
add empty check before getting optional value
pluto-han Mar 16, 2026
dd0ace9
Merge branch 'main' into fix-for-issue-14085
koppor Mar 16, 2026
71adb96
add javadoc and example to RelatedWorkSnippet.java
pluto-han Mar 16, 2026
98175dc
Update jabgui/src/main/java/org/jabref/gui/relatedwork/RelatedWorkRes…
pluto-han Mar 16, 2026
1ec6337
Merge remote-tracking branch 'origin/fix-for-issue-14085' into fix-fo…
pluto-han Mar 16, 2026
f3b12b2
Fix comment style
pluto-han Apr 4, 2026
3aebab4
Add backticks around `comment-{username}``
pluto-han Apr 4, 2026
703995b
Add @NullMarked
pluto-han Apr 4, 2026
ff0491b
Change parameter order
pluto-han Apr 4, 2026
a95837d
Change variable order
pluto-han Apr 4, 2026
f564f63
remove copyOf
pluto-han Apr 4, 2026
0bf0af3
remove copyOf
pluto-han Apr 5, 2026
fa587bd
remove `skipped`
pluto-han Apr 5, 2026
b1dca63
change comment style
pluto-han Apr 5, 2026
846875b
add comment
pluto-han Apr 5, 2026
22543d7
Add backticks around `comment-{username}`
pluto-han Apr 5, 2026
be7c4ee
Add more explanation in the comment
pluto-han Apr 5, 2026
9688e8b
Add "undefined" to `getCitationKey`
pluto-han Apr 5, 2026
0957641
get owner from preference
pluto-han Apr 5, 2026
9944d01
Add action helper to check if PDF file is present
pluto-han Apr 6, 2026
b2fe2a6
Hihglight non-editabel fileds differently
pluto-han Apr 6, 2026
d62b984
Update CHANGELOG.md
pluto-han Apr 6, 2026
f773117
Fix failed test
pluto-han Apr 6, 2026
1c65b9c
Focus related work text field, auto insert clipboard content
pluto-han Apr 6, 2026
559fb01
Use sealed interface instead of enum
pluto-han Apr 6, 2026
66dfb99
Merge branch 'main' into fix-for-issue-14085
pluto-han Apr 6, 2026
72a01c5
Fix failed tests
pluto-han Apr 6, 2026
5be52f3
Merge remote-tracking branch 'origin/fix-for-issue-14085' into fix-fo…
pluto-han Apr 6, 2026
8294c6f
Add logger
pluto-han Apr 6, 2026
a9226c3
Trigger CI
pluto-han Apr 7, 2026
39a2943
Replace all page separators to "-"
pluto-han Apr 7, 2026
3c2c6a3
Split RelatedWorkService to matcher and inserter
pluto-han Apr 7, 2026
5a0e3b3
Replace "[^a-z0-9]" as a constant NON_ALPHANUMERIC
pluto-han Apr 8, 2026
0ac6dc8
Merge branch 'main' into fix-for-issue-14085
pluto-han Apr 10, 2026
43d579d
use switch to replace ifelse
pluto-han Apr 10, 2026
6fd763e
use mock to create filepreference
pluto-han Apr 10, 2026
0cfce22
Merge remote-tracking branch 'origin/fix-for-issue-14085' into fix-fo…
pluto-han Apr 10, 2026
5d85486
Normalize linebreak
pluto-han Apr 10, 2026
b3a76a6
Add requirement
pluto-han Apr 10, 2026
1d95e03
Add requirement
pluto-han Apr 10, 2026
6540124
Fix md format fail
pluto-han Apr 10, 2026
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv

### Added

- We added a related work text extractor, which finds and inserts the related work text into bib entries from references in the texts. [#9840](https://github.com/JabRef/jabref/issues/9840)
- We added a hover button on group rows to quickly add a new group or subgroup. [#12289](https://github.com/JabRef/jabref/issues/12289)
- We added a shorthand for protecting terms in the fields: user can now select a text and type a opening curling brace to quickly wrap the selection in braces. [#15442](https://github.com/JabRef/jabref/pull/15442)
- We added fallback search for `[DATE]` patterns in the file finder, so that if an exact date match is not found, progressively less specific dates (year-month, then year) are tried. [#8152](https://github.com/JabRef/jabref/issues/8152)
Expand Down
16 changes: 16 additions & 0 deletions docs/requirements/dialog-with-text-input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
parent: Requirements
---
# Dialog with text input

## Automatic clipboard content detection and focus for text input
`req~textinput.clipboard.autofocus~1`

When a dialog with text input is opened:

- Text field should be focused.
- If the clipboard contains contents, it should be in the field and be marked.

Needs: impl

<!-- markdownlint-disable-file MD022 -->
22 changes: 22 additions & 0 deletions jabgui/src/main/java/org/jabref/gui/actions/ActionHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,28 @@ public static BooleanExpression isFilePresentForSelectedEntry(StateManager state
return BooleanExpression.booleanExpression(fileIsPresent);
}

public static BooleanExpression isPdfFilePresentForSelectedEntry(StateManager stateManager, CliPreferences preferences) {
ObservableList<BibEntry> selectedEntries = stateManager.getSelectedEntries();
Binding<Boolean> pdfFileIsPresent = EasyBind.valueAt(selectedEntries, 0).mapOpt(entry -> {
if (stateManager.getActiveDatabase().isEmpty()) {
return false;
}

return entry.getFiles().stream()
.filter(linkedFile -> linkedFile.getFileName()
.map(Path::of)
.map(FileUtil::isPDFFile)
.orElse(false))
.anyMatch(linkedFile -> FileUtil.find(
stateManager.getActiveDatabase().get(),
linkedFile.getLink(),
preferences.getFilePreferences())
.isPresent());
}).orElseOpt(false);

return BooleanExpression.booleanExpression(pdfFileIsPresent);
}

/// Check if at least one of the selected entries has linked files
/// <br>
/// Used in {@link org.jabref.gui.maintable.OpenSelectedEntriesFilesAction} when multiple entries selected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public enum StandardActions implements Action {
OPEN_EXTERNAL_FILE(Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE),
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),
EXTRACT_RELATED_WORK_COMMENTS(Localization.lang("Extract related work comments"), IconTheme.JabRefIcons.COMMENT),
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")),
Expand Down
2 changes: 2 additions & 0 deletions jabgui/src/main/java/org/jabref/gui/frame/MainMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.jabref.gui.preview.PreviewControls;
import org.jabref.gui.pseudonymize.PseudonymizeAction;
import org.jabref.gui.push.GuiPushToApplicationCommand;
import org.jabref.gui.relatedwork.RelatedWorkAction;
import org.jabref.gui.search.RebuildFulltextSearchIndexAction;
import org.jabref.gui.shared.ConnectToSharedDatabaseCommand;
import org.jabref.gui.shared.PullChangesFromSharedAction;
Expand Down Expand Up @@ -326,6 +327,7 @@ private void createMenu() {
factory.createMenuItem(StandardActions.NEW_SUB_LIBRARY_FROM_AUX, new NewSubLibraryAction(frame, stateManager, dialogService)),
factory.createMenuItem(StandardActions.NEW_LIBRARY_FROM_PDF_ONLINE, new NewLibraryFromPdfActionOnline(frame, stateManager, dialogService, preferences, taskExecutor)),
factory.createMenuItem(StandardActions.NEW_LIBRARY_FROM_PDF_OFFLINE, new NewLibraryFromPdfActionOffline(frame, stateManager, dialogService, preferences, taskExecutor)),
factory.createMenuItem(StandardActions.EXTRACT_RELATED_WORK_COMMENTS, new RelatedWorkAction(dialogService, stateManager, preferences)),
factory.createMenuItem(StandardActions.PSEUDONYMIZE_LIBRARY, new PseudonymizeAction(stateManager, dialogService, preferences)),

new SeparatorMenuItem(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.gui.preview.CopyCitationAction;
import org.jabref.gui.preview.PreviewPreferences;
import org.jabref.gui.relatedwork.RelatedWorkAction;
import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory;
import org.jabref.logic.citationstyle.CitationStyleOutputFormat;
import org.jabref.logic.importer.WebFetchers;
Expand Down Expand Up @@ -94,6 +95,7 @@ public static ContextMenu create(LibraryTab libraryTab,
factory.createMenuItem(StandardActions.OPEN_EXTERNAL_FILE, new OpenSelectedEntriesFilesAction(dialogService, stateManager, preferences, taskExecutor)),
extractFileReferencesOnline,
extractFileReferencesOffline,
factory.createMenuItem(StandardActions.EXTRACT_RELATED_WORK_COMMENTS, new RelatedWorkAction(dialogService, stateManager, preferences)),

factory.createMenuItem(StandardActions.OPEN_URL, new OpenUrlAction(dialogService, stateManager, preferences)),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ private void initializeLookupIdentifier() {
}

private void initializeInterpretCitations() {
// [impl->req~textinput.clipboard.autofocus~1]
interpretText.textProperty().bindBidirectional(viewModel.interpretTextProperty());
final String clipboardText = ClipBoardManager.getContents().trim();
if (!StringUtil.isBlank(clipboardText)) {
Expand Down Expand Up @@ -443,6 +444,7 @@ private void switchInterpretCitations() {
currentApproach = NewEntryDialogTab.INTERPRET_CITATIONS;
newEntryPreferences.setLatestApproach(NewEntryDialogTab.INTERPRET_CITATIONS);

// [impl->req~textinput.clipboard.autofocus~1]
if (interpretText != null) {
Platform.runLater(() -> interpretText.requestFocus());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.jabref.gui.relatedwork;

import java.nio.file.Path;
import java.util.Optional;

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.logic.l10n.Localization;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.LinkedFile;

public class RelatedWorkAction extends SimpleCommand {

private final DialogService dialogService;
private final StateManager stateManager;

public RelatedWorkAction(DialogService dialogService, StateManager stateManager, CliPreferences preferences) {
this.dialogService = dialogService;
this.stateManager = stateManager;
executable.bind(ActionHelper.needsDatabase(stateManager)
.and(ActionHelper.needsEntriesSelected(1, stateManager))
.and(ActionHelper.isPdfFilePresentForSelectedEntry(stateManager, preferences)));
}

@Override
public void execute() {
BibDatabaseContext databaseContext = stateManager.getActiveDatabase().orElseThrow();
BibEntry sourceEntry = stateManager.getSelectedEntries().getFirst();
Optional<LinkedFile> linkedPDFFile = sourceEntry.getFiles().stream()
.filter(this::isPDFLinkedFile)
.findFirst();

if (linkedPDFFile.isEmpty()) {
dialogService.showWarningDialogAndWait(
Localization.lang("No PDF files available"),
Localization.lang("Please attach PDF files")
);
return;
}

Optional<String> citationKey = sourceEntry.getCitationKey();
if (citationKey.isEmpty()) {
dialogService.showWarningDialogAndWait(
Localization.lang("Insert related work text"),
Localization.lang("Selected entry does not have an associated citation key.")
);
return;
}

dialogService.showCustomDialogAndWait(new RelatedWorkDialogView(
databaseContext,
sourceEntry,
linkedPDFFile.get(),
citationKey.get()
));
}

private boolean isPDFLinkedFile(LinkedFile linkedFile) {
return linkedFile.getFileName()
.map(Path::of)
.map(FileUtil::isPDFFile)
.orElse(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.jabref.gui.relatedwork;

import java.util.List;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

import org.jabref.gui.DialogService;
import org.jabref.gui.clipboard.ClipBoardManager;
import org.jabref.gui.util.BaseDialog;
import org.jabref.gui.util.ControlHelper;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.logic.relatedwork.RelatedWorkMatchResult;
import org.jabref.logic.util.strings.StringUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.LinkedFile;

import com.airhacks.afterburner.views.ViewLoader;
import jakarta.inject.Inject;

public class RelatedWorkDialogView extends BaseDialog<Void> {

private final BibDatabaseContext databaseContext;
private final BibEntry sourceEntry;
private final LinkedFile linkedFile;
private final String sourceEntryCitationKey;

@FXML private TextField entryField;
@FXML private TextField linkedFileField;
@FXML private TextField userNameField;
@FXML private TextArea relatedWorkTextArea;
@FXML private ButtonType parseButtonType;

@Inject private DialogService dialogService;
@Inject private CliPreferences preferences;
@Inject private BibEntryTypesManager entryTypesManager;

private RelatedWorkDialogViewModel viewModel;

public RelatedWorkDialogView(BibDatabaseContext databaseContext,
BibEntry sourceEntry,
LinkedFile linkedPdfFile,
String sourceEntryCitationKey) {
this.databaseContext = databaseContext;
this.sourceEntry = sourceEntry;
this.linkedFile = linkedPdfFile;
this.sourceEntryCitationKey = sourceEntryCitationKey;

setTitle(Localization.lang("Insert related work text"));

ViewLoader.view(this).load().setAsDialogPane(this);

ControlHelper.setAction(parseButtonType, getDialogPane(), event -> viewModel.matchRelatedWork().ifPresent(this::openResultDialog));

Button parseButton = (Button) getDialogPane().lookupButton(parseButtonType);
parseButton.disableProperty().bind(viewModel.parseDisabledProperty());
}

@FXML
private void initialize() {
this.viewModel = new RelatedWorkDialogViewModel(
databaseContext,
sourceEntry,
linkedFile,
sourceEntryCitationKey,
dialogService,
preferences,
entryTypesManager
);

this.entryField.textProperty().bind(viewModel.sourceEntryCitationKeyProperty());
this.linkedFileField.textProperty().bind(viewModel.linkedPDFFileProperty());
this.userNameField.textProperty().bind(viewModel.userNameProperty());
this.relatedWorkTextArea.textProperty().bindBidirectional(viewModel.relatedWorkTextProperty());

// [impl->req~textinput.clipboard.autofocus~1]
String clipboardText = ClipBoardManager.getContents().trim();
if (!StringUtil.isBlank(clipboardText)) {
relatedWorkTextArea.setText(clipboardText);
relatedWorkTextArea.selectAll();
}

Platform.runLater(relatedWorkTextArea::requestFocus);
}

private void openResultDialog(List<RelatedWorkMatchResult> matchedResults) {
dialogService.showCustomDialogAndWait(new RelatedWorkResultDialogView(sourceEntry, matchedResults, viewModel.userNameProperty().get()));
}
}
Loading
Loading