Enable the exploration of bib entries' relations (cited by and citing) #10324
Conversation
Co-authored-by: Tim Bachmann <58782027+timbachmann@users.noreply.github.com> Co-authored-by: Raphael Kreft <r.kreft@unibas.ch> Co-authored-by: Marcel Luethi <marcel.luethi@unibas.ch> Co-authored-by: olivierM <olivier.mattmann@stud.unibas.ch> Co-authored-by: matiascg <matiascargon@hotmail.com>
- Until we implement pagination, fetching 1000 citations/references seems fine.
|
Your code currently does not meet JabRef's code guidelines. The tool reviewdog already placed comments on GitHub to indicate the places. See the tab "Files" in you PR. Please carefully follow the setup guide for the codestyle. Afterwards, please run checkstyle locally and fix the issues. More information on code quality in JabRef is available at https://devdocs.jabref.org/getting-into-the-code/development-strategy.html. |
|
Can I ask: is this the same as this request I made some time ago? |
|
@the-dino-girl It's similar to that, but the references we get from a public web API (similar to how fetchers work). It's also possible to get bib entries that cites the selected entry. It's under the "cited by" section. |
|
Can't wait for this feature! (Please add new translation strings if they are missing. I'm a jabref translator) 😍😍😍 |
You can download the current build at https://builds.jabref.org/pull/10324/merge and report issues here. (This is what the comment #10324 (comment) means -- grab the binary and play around with it) |
|
The build for this PR is no longer available. Please visit https://builds.jabref.org/main/ for the latest build. |
| import org.jabref.model.entry.BibEntry; | ||
| import org.jabref.model.entry.identifier.DOI; | ||
|
|
||
| public class BibEntryRelationsCache { |
There was a problem hiding this comment.
For the moment this is okay, but we could store it in MV files as well or use something like caffeeine https://medium.com/outbrain-engineering/oh-my-guava-we-are-moving-to-caffeine-99387819fdbb
There was a problem hiding this comment.
We already have a dependency on h2 MVStore, we could use that.
There was a problem hiding this comment.
Yes, like the journal abbreviation stuff. Write the stuff to a db int he user's app data dir
|
Cool feature! Need to try this! |
| /** | ||
| * Method to start search for relations and display them in the associated ListView | ||
| * | ||
| * @param entry BibEntry currently selected in Jabref Database | ||
| * @param listView ListView to use | ||
| * @param abortButton Button to stop the search | ||
| * @param refreshButton refresh Button to use | ||
| * @param searchType type of search (CITING / CITEDBY) | ||
| */ | ||
| private void searchForRelations(BibEntry entry, CheckListView<CitationRelationItem> listView, Button abortButton, | ||
| Button refreshButton, CitationFetcher.SearchType searchType, Button importButton, | ||
| ProgressIndicator progress, boolean shouldRefresh) { | ||
| if (entry.getDOI().isEmpty()) { | ||
| hideNodes(abortButton, progress); | ||
| showNodes(refreshButton); | ||
| listView.getItems().clear(); | ||
| listView.setPlaceholder( | ||
| new Label(Localization.lang("The selected entry doesn't have a DOI linked to it. Lookup a DOI and try again."))); | ||
| return; | ||
| } | ||
|
|
||
| ObservableList<CitationRelationItem> observableList = FXCollections.observableArrayList(); | ||
|
|
||
| listView.setItems(observableList); | ||
|
|
||
| if (citingTask != null && !citingTask.isCanceled() && searchType.equals(CitationFetcher.SearchType.CITING)) { | ||
| citingTask.cancel(); | ||
| } else if (citedByTask != null && !citedByTask.isCanceled() && searchType.equals(CitationFetcher.SearchType.CITED_BY)) { | ||
| citedByTask.cancel(); | ||
| } | ||
|
|
||
| BackgroundTask<List<BibEntry>> task; | ||
|
|
||
| if (searchType.equals(CitationFetcher.SearchType.CITING)) { | ||
| task = BackgroundTask.wrap(() -> { | ||
| if (shouldRefresh) { | ||
| bibEntryRelationsRepository.forceRefreshReferences(entry); | ||
| } | ||
| return bibEntryRelationsRepository.getReferences(entry); | ||
| }); | ||
| citingTask = task; | ||
| } else { | ||
| task = BackgroundTask.wrap(() -> { | ||
| if (shouldRefresh) { | ||
| bibEntryRelationsRepository.forceRefreshCitations(entry); | ||
| } | ||
| return bibEntryRelationsRepository.getCitations(entry); | ||
| }); | ||
| citedByTask = task; | ||
| } | ||
|
|
||
| task.onRunning(() -> prepareToSearchForRelations(abortButton, refreshButton, importButton, progress, task)) | ||
| .onSuccess(fetchedList -> onSearchForRelationsSucceed(entry, listView, abortButton, refreshButton, | ||
| searchType, importButton, progress, fetchedList, observableList)) | ||
| .onFailure(exception -> { | ||
| LOGGER.error("Error while fetching citing Articles", exception); | ||
| hideNodes(abortButton, progress, importButton); | ||
| listView.setPlaceholder(new Label(Localization.lang("Error while fetching citing entries: %0", | ||
| exception.getMessage()))); | ||
|
|
||
| refreshButton.setVisible(true); | ||
| dialogService.notify(exception.getMessage()); | ||
| }) | ||
| .executeWith(Globals.TASK_EXECUTOR); | ||
| } | ||
|
|
||
| private void onSearchForRelationsSucceed(BibEntry entry, CheckListView<CitationRelationItem> listView, | ||
| Button abortButton, Button refreshButton, | ||
| CitationFetcher.SearchType searchType, Button importButton, | ||
| ProgressIndicator progress, List<BibEntry> fetchedList, | ||
| ObservableList<CitationRelationItem> observableList) { | ||
| hideNodes(abortButton, progress); | ||
|
|
||
| observableList.setAll(fetchedList.stream().map(entr -> new CitationRelationItem(entr, false)) | ||
| .collect(Collectors.toList())); | ||
|
|
||
| if (!observableList.isEmpty()) { | ||
| listView.refresh(); | ||
| } else { | ||
| Label placeholder = new Label(Localization.lang("No articles found")); | ||
| listView.setPlaceholder(placeholder); | ||
| } | ||
| BooleanBinding booleanBind = Bindings.isEmpty(listView.getCheckModel().getCheckedItems()); | ||
| importButton.disableProperty().bind(booleanBind); | ||
| importButton.setOnMouseClicked(event -> importEntries(listView.getCheckModel().getCheckedItems(), searchType, entry)); | ||
| showNodes(refreshButton, importButton); | ||
| } | ||
|
|
||
| private void prepareToSearchForRelations(Button abortButton, Button refreshButton, Button importButton, | ||
| ProgressIndicator progress, BackgroundTask<List<BibEntry>> task) { | ||
| showNodes(abortButton, progress); | ||
| hideNodes(refreshButton, importButton); | ||
|
|
||
| abortButton.setOnAction(event -> { | ||
| hideNodes(abortButton, progress, importButton); | ||
| showNodes(refreshButton); | ||
| task.cancel(); | ||
| dialogService.notify(Localization.lang("Search aborted!")); | ||
| }); | ||
| } | ||
|
|
||
| private void hideNodes(Node... nodes) { | ||
| Arrays.stream(nodes).forEach(node -> node.setVisible(false)); | ||
| } | ||
|
|
||
| private void showNodes(Node... nodes) { | ||
| Arrays.stream(nodes).forEach(node -> node.setVisible(true)); | ||
| } | ||
|
|
||
| // Absolute-phase phenomena in photoionization with few-cycle laser pulses | ||
|
|
||
| /** | ||
| * Function to import selected entries to the database. Also writes the entries to import to the CITING/CITED field | ||
| * | ||
| * @param entriesToImport entries to import | ||
| */ | ||
| private void importEntries(List<CitationRelationItem> entriesToImport, CitationFetcher.SearchType searchType, BibEntry entry) { | ||
| citingTask.cancel(); | ||
| citedByTask.cancel(); | ||
| List<BibEntry> entries = entriesToImport.stream().map(CitationRelationItem::getEntry).collect(Collectors.toList()); | ||
| ImportHandler importHandler = new ImportHandler( | ||
| databaseContext, | ||
| preferencesService, | ||
| fileUpdateMonitor, | ||
| undoManager, | ||
| stateManager, | ||
| dialogService, | ||
| Globals.TASK_EXECUTOR); | ||
| importHandler.importEntries(entries); | ||
|
|
||
| dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); | ||
| } |
There was a problem hiding this comment.
I have the strong suspicion, that some of this code belongs into a ViewModel
There was a problem hiding this comment.
It surely does, but I thought we release the feature now letting users try it out and do some refactoring while working on the known limitations in later PRs.
There was a problem hiding this comment.
ok, im fine with that. let ua just not forget about this, maybe an issue in the maintainers focus or sthg
koppor
left a comment
There was a problem hiding this comment.
Thank you for working on this!
We fixed the openrewrite complains by running ./gradlew rewriteRun (at 14ecf06 (#10324)).
Will merge as soon as tests are green.
Follow-up issues created (in the melting pot).
Lets see, what the users will tell!
A continuation to #7160.
Closes #6187
Known Limitations
Screenshots
Mandatory checks
CHANGELOG.mddescribed in a way that is understandable for the average user (if applicable)