Skip to content

Commit e1d0d66

Browse files
authored
Automatic lookup of DOI at citation relations (#13539)
* Some initial changes + split of the placeholder to label and hyperlink. * Commit before switching to different branch. * Cited by panel ready. * Cited by panel ready. * Finished DOI lookup, add notification about not found DOI. * Add messages to JabRef_en.properties. Modified lang files rolled back. * Change "Up" to "up" in the messages. * Remove exclamation from the message. * Move methods to the original place in the file.
1 parent b4b5094 commit e1d0d66

File tree

5 files changed

+138
-100
lines changed

5 files changed

+138
-100
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
1111

1212
### Added
1313

14+
- We added automatic lookup of DOI at citation relations [#13234](https://github.com/JabRef/jabref/issues/13234)
1415
- We added focus on the field Link in the "Add file link" dialog. [#13486](https://github.com/JabRef/jabref/issues/13486)
1516
- We introduced a settings parameter to manage citations' relations local storage time-to-live with a default value set to 30 days. [#11189](https://github.com/JabRef/jabref/issues/11189)
1617
- We distribute arm64 images for Linux. [#10842](https://github.com/JabRef/jabref/issues/10842)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.jabref.gui.entryeditor.citationrelationtab;
2+
3+
import javafx.scene.control.Button;
4+
import javafx.scene.control.ProgressIndicator;
5+
6+
import org.jabref.logic.importer.fetcher.citation.CitationFetcher;
7+
import org.jabref.model.entry.BibEntry;
8+
9+
import org.controlsfx.control.CheckListView;
10+
11+
public record CitationComponents(
12+
BibEntry entry,
13+
CheckListView<CitationRelationItem> listView,
14+
Button abortButton,
15+
Button refreshButton,
16+
CitationFetcher.SearchType searchType,
17+
Button importButton,
18+
ProgressIndicator progress) {
19+
}

jabgui/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java

Lines changed: 112 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import javafx.scene.control.Button;
2121
import javafx.scene.control.ButtonType;
2222
import javafx.scene.control.DialogPane;
23+
import javafx.scene.control.Hyperlink;
2324
import javafx.scene.control.Label;
2425
import javafx.scene.control.ProgressIndicator;
2526
import javafx.scene.control.ScrollPane;
@@ -52,6 +53,7 @@
5253
import org.jabref.logic.citation.SearchCitationsRelationsService;
5354
import org.jabref.logic.database.DuplicateCheck;
5455
import org.jabref.logic.exporter.BibWriter;
56+
import org.jabref.logic.importer.fetcher.CrossRef;
5557
import org.jabref.logic.importer.fetcher.citation.CitationFetcher;
5658
import org.jabref.logic.l10n.Localization;
5759
import org.jabref.logic.os.OS;
@@ -199,48 +201,34 @@ private SplitPane getPaneAndStartSearch(BibEntry entry) {
199201
citingVBox.getChildren().addAll(citingHBox, citingListView);
200202
citedByVBox.getChildren().addAll(citedByHBox, citedByListView);
201203

202-
refreshCitingButton.setOnMouseClicked(_ -> {
203-
searchForRelations(
204-
entry,
205-
citingListView,
206-
abortCitingButton,
207-
refreshCitingButton,
208-
CitationFetcher.SearchType.CITES,
209-
importCitingButton,
210-
citingProgress);
211-
});
204+
CitationComponents citingComponents = new CitationComponents(
205+
entry,
206+
citingListView,
207+
abortCitingButton,
208+
refreshCitingButton,
209+
CitationFetcher.SearchType.CITES,
210+
importCitingButton,
211+
citingProgress);
212212

213-
refreshCitedByButton.setOnMouseClicked(_ -> searchForRelations(
214-
entry,
215-
citedByListView,
213+
CitationComponents citedByComponents = new CitationComponents(
214+
entry,
215+
citedByListView,
216216
abortCitedButton,
217-
refreshCitedByButton,
218-
CitationFetcher.SearchType.CITED_BY,
219-
importCitedByButton,
220-
citedByProgress));
217+
refreshCitedByButton,
218+
CitationFetcher.SearchType.CITED_BY,
219+
importCitedByButton,
220+
citedByProgress);
221+
222+
refreshCitingButton.setOnMouseClicked(_ -> searchForRelations(citingComponents, citedByComponents));
223+
refreshCitedByButton.setOnMouseClicked(_ -> searchForRelations(citedByComponents, citingComponents));
221224

222225
// Create SplitPane to hold all nodes above
223226
SplitPane container = new SplitPane(citingVBox, citedByVBox);
224227
styleFetchedListView(citedByListView);
225228
styleFetchedListView(citingListView);
226229

227-
searchForRelations(
228-
entry,
229-
citingListView,
230-
abortCitingButton,
231-
refreshCitingButton,
232-
CitationFetcher.SearchType.CITES,
233-
importCitingButton,
234-
citingProgress);
235-
236-
searchForRelations(
237-
entry,
238-
citedByListView,
239-
abortCitedButton,
240-
refreshCitedByButton,
241-
CitationFetcher.SearchType.CITED_BY,
242-
importCitedByButton,
243-
citedByProgress);
230+
searchForRelations(citingComponents, citedByComponents);
231+
searchForRelations(citedByComponents, citingComponents);
244232

245233
return container;
246234
}
@@ -271,9 +259,9 @@ private void styleFetchedListView(CheckListView<CitationRelationItem> listView)
271259
jumpTo.getStyleClass().add("addEntryButton");
272260
jumpTo.setOnMouseClicked(_ -> jumpToEntry(entry));
273261
hContainer.setOnMouseClicked(event -> {
274-
if (event.getClickCount() == 2) {
275-
jumpToEntry(entry);
276-
}
262+
if (event.getClickCount() == 2) {
263+
jumpToEntry(entry);
264+
}
277265
});
278266
vContainer.getChildren().add(jumpTo);
279267

@@ -423,59 +411,89 @@ protected void bindToEntry(BibEntry entry) {
423411
setContent(getPaneAndStartSearch(entry));
424412
}
425413

426-
/**
427-
* Method to start search for relations and display them in the associated ListView
428-
*
429-
* @param entry BibEntry currently selected in Jabref Database
430-
* @param listView ListView to use
431-
* @param abortButton Button to stop the search
432-
* @param refreshButton refresh Button to use
433-
* @param searchType type of search (CITING / CITEDBY)
434-
*/
435-
private void searchForRelations(BibEntry entry, CheckListView<CitationRelationItem> listView, Button abortButton,
436-
Button refreshButton, CitationFetcher.SearchType searchType, Button importButton,
437-
ProgressIndicator progress) {
438-
if (entry.getDOI().isEmpty()) {
439-
hideNodes(abortButton, progress);
440-
showNodes(refreshButton);
441-
listView.getItems().clear();
442-
listView.setPlaceholder(
443-
new Label(Localization.lang("The selected entry doesn't have a DOI linked to it. Lookup a DOI and try again.")));
414+
private void searchForRelations(CitationComponents citationComponents,
415+
CitationComponents otherCitationComponents) {
416+
if (citationComponents.entry().getDOI().isEmpty()) {
417+
setUpEmptyPanel(citationComponents, otherCitationComponents);
444418
return;
445419
}
420+
executeSearch(citationComponents);
421+
}
446422

447-
ObservableList<CitationRelationItem> observableList = FXCollections.observableArrayList();
423+
private void setUpEmptyPanel(CitationComponents citationComponents,
424+
CitationComponents otherCitationComponents) {
425+
hideNodes(citationComponents.abortButton(), citationComponents.progress());
426+
showNodes(citationComponents.refreshButton());
427+
428+
HBox hBox = new HBox();
429+
Label label = new Label(Localization.lang("The selected entry doesn't have a DOI linked to it."));
430+
Hyperlink link = new Hyperlink(Localization.lang("Look up a DOI and try again."));
431+
432+
link.setOnAction(e -> {
433+
CrossRef doiFetcher = new CrossRef();
434+
435+
BackgroundTask.wrap(() -> doiFetcher.findIdentifier(citationComponents.entry()))
436+
.onRunning(() -> {
437+
showNodes(citationComponents.progress(), otherCitationComponents.progress());
438+
setLabelOn(citationComponents.listView(), Localization.lang("Looking up DOI..."));
439+
setLabelOn(otherCitationComponents.listView(), Localization.lang("Looking up DOI..."));
440+
})
441+
.onSuccess(identifier -> {
442+
if (identifier.isPresent()) {
443+
citationComponents.entry().setField(StandardField.DOI, identifier.get().asString());
444+
executeSearch(citationComponents);
445+
executeSearch(otherCitationComponents);
446+
} else {
447+
dialogService.notify(Localization.lang("No DOI found"));
448+
setUpEmptyPanel(citationComponents, otherCitationComponents);
449+
setUpEmptyPanel(otherCitationComponents, citationComponents);
450+
}
451+
}).onFailure(ex -> {
452+
hideNodes(citationComponents.progress(), otherCitationComponents.progress());
453+
setLabelOn(citationComponents.listView(), "Error " + ex.getMessage());
454+
setLabelOn(otherCitationComponents.listView(), "Error " + ex.getMessage());
455+
}).executeWith(taskExecutor);
456+
});
457+
458+
hBox.getChildren().add(label);
459+
hBox.getChildren().add(link);
460+
hBox.setSpacing(2d);
461+
hBox.setStyle("-fx-alignment: center;");
462+
hBox.setFillHeight(true);
463+
464+
citationComponents.listView().getItems().clear();
465+
citationComponents.listView().setPlaceholder(hBox);
466+
}
467+
468+
private static void setLabelOn(CheckListView<CitationRelationItem> listView, String message) {
469+
Label lookingUpDoiLabel = new Label(message);
470+
listView.getItems().clear();
471+
listView.setPlaceholder(lookingUpDoiLabel);
472+
}
448473

449-
listView.setItems(observableList);
474+
private void executeSearch(CitationComponents citationComponents) {
475+
ObservableList<CitationRelationItem> observableList = FXCollections.observableArrayList();
476+
citationComponents.listView().setItems(observableList);
450477

451478
// TODO: It should not be possible to cancel a search task that is already running for same tab
452-
if (citingTask != null && !citingTask.isCancelled() && searchType == CitationFetcher.SearchType.CITES) {
479+
if (citingTask != null && !citingTask.isCancelled() && citationComponents.searchType() == CitationFetcher.SearchType.CITES) {
453480
citingTask.cancel();
454-
} else if (citedByTask != null && !citedByTask.isCancelled() && searchType == CitationFetcher.SearchType.CITED_BY) {
481+
} else if (citedByTask != null && !citedByTask.isCancelled() && citationComponents.searchType() == CitationFetcher.SearchType.CITED_BY) {
455482
citedByTask.cancel();
456483
}
457484

458-
this.createBackgroundTask(entry, searchType)
459-
.consumeOnRunning(task -> prepareToSearchForRelations(
460-
abortButton, refreshButton, importButton, progress, task
461-
))
462-
.onSuccess(fetchedList -> onSearchForRelationsSucceed(
463-
entry,
464-
listView,
465-
abortButton,
466-
refreshButton,
467-
searchType,
468-
importButton,
469-
progress,
470-
fetchedList,
471-
observableList
485+
this.createBackgroundTask(citationComponents.entry(), citationComponents.searchType())
486+
.consumeOnRunning(task -> prepareToSearchForRelations(citationComponents, task))
487+
.onSuccess(fetchedList -> onSearchForRelationsSucceed(citationComponents,
488+
fetchedList,
489+
observableList
472490
))
473491
.onFailure(exception -> {
474492
LOGGER.error("Error while fetching citing Articles", exception);
475-
hideNodes(abortButton, progress, importButton);
476-
listView.setPlaceholder(new Label(Localization.lang("Error while fetching citing entries: %0",
493+
hideNodes(citationComponents.abortButton(), citationComponents.progress(), citationComponents.importButton());
494+
citationComponents.listView().setPlaceholder(new Label(Localization.lang("Error while fetching citing entries: %0",
477495
exception.getMessage())));
478-
refreshButton.setVisible(true);
496+
citationComponents.refreshButton().setVisible(true);
479497
dialogService.notify(exception.getMessage());
480498
})
481499
.executeWith(taskExecutor);
@@ -503,15 +521,13 @@ private BackgroundTask<List<BibEntry>> createBackgroundTask(
503521
};
504522
}
505523

506-
private void onSearchForRelationsSucceed(BibEntry entry, CheckListView<CitationRelationItem> listView,
507-
Button abortButton, Button refreshButton,
508-
CitationFetcher.SearchType searchType, Button importButton,
509-
ProgressIndicator progress, List<BibEntry> fetchedList,
524+
private void onSearchForRelationsSucceed(CitationComponents citationComponents,
525+
List<BibEntry> fetchedList,
510526
ObservableList<CitationRelationItem> observableList) {
511-
hideNodes(abortButton, progress);
512527

513-
BibDatabase database = stateManager.getActiveDatabase().map(BibDatabaseContext::getDatabase)
514-
.orElse(new BibDatabase());
528+
hideNodes(citationComponents.abortButton(), citationComponents.progress());
529+
530+
BibDatabase database = stateManager.getActiveDatabase().map(BibDatabaseContext::getDatabase).orElse(new BibDatabase());
515531
observableList.setAll(
516532
fetchedList.stream().map(entr ->
517533
duplicateCheck.containsDuplicate(
@@ -524,27 +540,26 @@ private void onSearchForRelationsSucceed(BibEntry entry, CheckListView<CitationR
524540
);
525541

526542
if (!observableList.isEmpty()) {
527-
listView.refresh();
543+
citationComponents.listView().refresh();
528544
} else {
529545
Label placeholder = new Label(Localization.lang("No articles found"));
530-
listView.setPlaceholder(placeholder);
546+
citationComponents.listView().setPlaceholder(placeholder);
531547
}
532-
BooleanBinding booleanBind = Bindings.isEmpty(listView.getCheckModel().getCheckedItems());
533-
importButton.disableProperty().bind(booleanBind);
534-
importButton.setOnMouseClicked(event -> importEntries(listView.getCheckModel().getCheckedItems(), searchType, entry));
535-
showNodes(refreshButton, importButton);
548+
BooleanBinding booleanBind = Bindings.isEmpty(citationComponents.listView().getCheckModel().getCheckedItems());
549+
citationComponents.importButton().disableProperty().bind(booleanBind);
550+
citationComponents.importButton().setOnMouseClicked(event -> importEntries(citationComponents.listView().getCheckModel().getCheckedItems(), citationComponents.searchType(), citationComponents.entry()));
551+
showNodes(citationComponents.refreshButton(), citationComponents.importButton());
536552
}
537553

538-
private void prepareToSearchForRelations(Button abortButton, Button refreshButton, Button importButton,
539-
ProgressIndicator progress, BackgroundTask<List<BibEntry>> task) {
540-
showNodes(abortButton, progress);
541-
hideNodes(refreshButton, importButton);
554+
private void prepareToSearchForRelations(CitationComponents citationComponents, BackgroundTask<List<BibEntry>> task) {
555+
showNodes(citationComponents.abortButton(), citationComponents.progress());
556+
hideNodes(citationComponents.refreshButton(), citationComponents.importButton());
542557

543-
abortButton.setOnAction(event -> {
544-
hideNodes(abortButton, progress, importButton);
545-
showNodes(refreshButton);
558+
citationComponents.abortButton().setOnAction(event -> {
559+
hideNodes(citationComponents.abortButton(), citationComponents.progress(), citationComponents.importButton());
560+
showNodes(citationComponents.refreshButton());
546561
task.cancel();
547-
dialogService.notify(Localization.lang("Search aborted!"));
562+
dialogService.notify(Localization.lang("Search aborted."));
548563
});
549564
}
550565

jablib/src/main/resources/l10n/JabRef_en.properties

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,14 +2801,17 @@ Miscellaneous=Miscellaneous
28012801
File-related=File-related
28022802
28032803
Add\ selected\ entry(s)\ to\ library=Add selected entry(s) to library
2804-
The\ selected\ entry\ doesn't\ have\ a\ DOI\ linked\ to\ it.\ Lookup\ a\ DOI\ and\ try\ again.=The selected entry doesn't have a DOI linked to it. Lookup a DOI and try again.
2804+
The\ selected\ entry\ doesn't\ have\ a\ DOI\ linked\ to\ it.=The selected entry doesn't have a DOI linked to it.
2805+
Look\ up\ a\ DOI\ and\ try\ again.=Look up a DOI and try again.
2806+
Looking\ up\ DOI...=Looking up DOI...
2807+
No\ DOI\ found=No DOI found
28052808
Cited\ By=Cited By
28062809
Cites=Cites
28072810
No\ articles\ found=No articles found
28082811
Restart\ search=Restart search
28092812
Cancel\ search=Cancel search
28102813
Select\ entry=Select entry
2811-
Search\ aborted!=Search aborted!
2814+
Search\ aborted.=Search aborted.
28122815
Citation\ relations=Citation relations
28132816
Show\ articles\ related\ by\ citation=Show articles related by citation
28142817
Error\ while\ fetching\ citing\ entries\:\ %0=Error while fetching citing entries: %0

jablib/src/main/resources/l10n/JabRef_zh_CN.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,7 @@ Convert\ to\ BibTeX\ format\ (e.g.,\ store\ publication\ date\ in\ year\ and\ mo
12971297
Deprecated\ fields=废弃的字段
12981298

12991299
Shows\ fields\ having\ a\ successor\ in\ biblatex.=Shows fields having a successor in biblatex.
1300-
Shows\ fields\ having\ a\ successor\ in\ biblatex.\nFor\ instance,\ the\ publication\ month\ should\ be\ part\ of\ the\ date\ field.\nUse\ the\ Clean\ up\ Entries\ functionality\ to\ convert\ the\ entry\ to\ biblatex.=显示在biblatex中具有后继关系的field。\n例如,发布月份(publication month)应当是日期(date)的一部分。\n使用"清理记录"功能来转换条目为biblatex。
1300+
Shows\ fields\ having\ a\ successor\ in\ biblatex.\nFor\ instance,\ the\ publication\ month\ should\ be\ part\ of\ the\ date\ field.\nUse\ the\ Clean\ up\ Entries\ functionality\ to\ convert\ the\ entry\ to\ biblatex.=显示在biblatex中具有后继关系的field。\n例如,发布月份(publication month)应当是日期(date)的一部分。\n使用"清理记录"功能来转换条目为biblatex。
13011301

13021302

13031303
No\ read\ status\ information=无阅读情况信息

0 commit comments

Comments
 (0)