Skip to content

Commit bec3e93

Browse files
committed
Merge remote-tracking branch 'upstream/main'
* upstream/main: Bump jablib/src/main/resources/csl-locales from `3bad433` to `ea1b54f` (#13565) New Crowdin updates (#13562) Add a new field for citation count (#13531) Automatic lookup of DOI at citation relations (#13539) Update dependency com.konghq:unirest-modules-gson to v4.5.0 (#13557) Group tab is now empty when there are no libraries open (#13473)
2 parents a0a2ca0 + 61eb81d commit bec3e93

32 files changed

+655
-258
lines changed

.jbang/JabSrvLauncher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
//DEPS info.picocli:picocli:4.7.7
6262
//DEPS org.postgresql:postgresql:42.7.7
6363
//DEPS org.bouncycastle:bcprov-jdk18on:1.81
64-
//DEPS com.konghq:unirest-modules-gson:4.4.12
64+
//DEPS com.konghq:unirest-modules-gson:4.5.0
6565
//DEPS jakarta.ws.rs:jakarta.ws.rs-api:4.0.0
6666
//DEPS org.glassfish.jersey.core:jersey-server:3.1.10
6767
//DEPS org.glassfish.jersey.inject:jersey-hk2:3.1.10
@@ -73,7 +73,7 @@
7373
//DEPS org.glassfish.grizzly:grizzly-framework:4.0.2
7474
//DEPS jakarta.validation:jakarta.validation-api:3.1.1
7575
//DEPS org.hibernate.validator:hibernate-validator:9.0.1.Final
76-
//DEPS com.konghq:unirest-modules-gson:4.4.12
76+
//DEPS com.konghq:unirest-modules-gson:4.5.0
7777
//DEPS com.google.guava:guava:33.4.8-jre
7878
//DEPS org.jabref:afterburner.fx:2.0.0
7979
//DEPS net.harawata:appdirs:1.4.0

CHANGELOG.md

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

1212
### Added
1313

14+
- We added a field for the citation count field on the General tab. [#13477](https://github.com/JabRef/jabref/issues/13477)
15+
- We added automatic lookup of DOI at citation relations [#13234](https://github.com/JabRef/jabref/issues/13234)
1416
- We added focus on the field Link in the "Add file link" dialog. [#13486](https://github.com/JabRef/jabref/issues/13486)
1517
- 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)
1618
- We distribute arm64 images for Linux. [#10842](https://github.com/JabRef/jabref/issues/10842)
@@ -78,6 +80,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
7880
- We fixed an issue where Document Viewer showed technical exceptions when opening entries with non-PDF files. [#13198](https://github.com/JabRef/jabref/issues/13198)
7981
- When creating a library, if you drag a PDF file containing only a single column, the dialog will now automatically close. [#13262](https://github.com/JabRef/jabref/issues/13262)
8082
- We fixed an issue where the tab showing the fulltext search results would appear blank after switching library. [#13241](https://github.com/JabRef/jabref/issues/13241)
83+
- We fixed an issue where the groups were still displayed after closing all libraries. [#13382](https://github.com/JabRef/jabref/issues/13382)
8184
- Enhanced field selection logic in the Merge Entries dialog when fetching from DOI to prefer valid years and entry types. [#12549](https://github.com/JabRef/jabref/issues/12549)
8285

8386
### Removed

build-logic/src/main/kotlin/org.jabref.gradle.base.dependency-rules.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,9 @@ extraJavaModuleInfo {
274274
module("org.xmlunit:xmlunit-matchers", "org.xmlunit.matchers") {
275275
exportAllPackages()
276276
requires("java.logging")
277-
requires("org.xmlunit")
277+
requires("java.xml")
278278
requires("org.hamcrest")
279+
requires("org.xmlunit")
279280
}
280281
module("org.xmlunit:xmlunit-placeholders", "org.xmlunit.placeholder")
281282

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

0 commit comments

Comments
 (0)