-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Add LaTeX citations tab to the entry editor #5137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
davidemdot
merged 34 commits into
JabRef:latexintegration
from
davidemdot:latexintegration-entryeditortab
Jul 29, 2019
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
a13e3b2
Update EntryEditor for using PreferencesService
davidemdot fedda55
Add LaTeX references tab option to entry editor preferences
davidemdot 4214103
Add getCitationsByKey(BibEntry) method in TexParserResult
davidemdot 4ba7f0d
Add LaTeX references tab to the entry editor
davidemdot d1fc7b3
Add missing localization keys
davidemdot 145b631
Fix bug related to the display of results
davidemdot cba1949
Replace Boolean with boolean type in preferences
davidemdot 47deee4
Rename feature-related stuff (references -> citations)
davidemdot 4d7256d
Update CHANGELOG.md
davidemdot 04d1a5f
Improve exception handling and add search cancellation
davidemdot 0d41f30
Update DefaultTexParser for avoiding ClosedByInterruptException when …
davidemdot 0095bed
Update EntryEditor for adding @Inject uses
davidemdot de0db44
Fix bug in EntryEditor (setOnDragDropped event)
davidemdot e6722ee
Merge remote-tracking branch 'origin/master' into latexintegration-en…
davidemdot b1c7cb6
Update logger messages in cancelSearch()
davidemdot 824ba0d
Update LaTeX citations tab for using a enum status property
davidemdot 1fd6d4e
Merge branch 'master' into latexintegration-entryeditortab
davidemdot ce4f925
Improve performance in the entry editor tab by searching for only the…
davidemdot 00287d8
Add default case to bindToEntry() in LatexCitationsTab
davidemdot b2c75cb
Update for adding small improvements
davidemdot 2db46d2
Improve performance and exception handling
davidemdot 2b700f1
Update error message for entries without BibTeX key
davidemdot 3fd9c36
Update GUI classes for public access
davidemdot 4c88528
Fix minor issues
davidemdot 0dbd084
Update for improving code
davidemdot 2a3f4ac
Update for adding the last improvements
davidemdot e4c0e14
Update for code refining
davidemdot de5d705
Set the search pane in LatexCitationsTab just once
davidemdot 3bb24a6
Update LatexCitationsTabViewModel for avoiding 'orElse(null)'
davidemdot ee1501e
Update TexParserResult for avoiding 'orElse(null)'
davidemdot 5cc4622
Update DefaultTexParser for explaining when and why it skips the cita…
davidemdot 3d019db
Change toString() methods
davidemdot 7adf03a
Add a new JabRefIcons.LATEX_CITATIONS
davidemdot 34713f5
Fix all issues from reviews of #5137
davidemdot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 76 additions & 70 deletions
146
src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 122 additions & 0 deletions
122
src/main/java/org/jabref/gui/entryeditor/LatexCitationsTab.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| package org.jabref.gui.entryeditor; | ||
|
|
||
| import java.nio.file.Path; | ||
| import java.util.Optional; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import javafx.scene.control.ProgressIndicator; | ||
| import javafx.scene.control.ScrollPane; | ||
| import javafx.scene.control.Tooltip; | ||
| import javafx.scene.layout.StackPane; | ||
| import javafx.scene.layout.VBox; | ||
| import javafx.scene.text.Text; | ||
|
|
||
| import org.jabref.gui.icon.IconTheme; | ||
| import org.jabref.gui.util.TaskExecutor; | ||
| import org.jabref.logic.l10n.Localization; | ||
| import org.jabref.model.database.BibDatabaseContext; | ||
| import org.jabref.model.entry.BibEntry; | ||
| import org.jabref.preferences.PreferencesService; | ||
|
|
||
| import org.fxmisc.easybind.EasyBind; | ||
|
|
||
| public class LatexCitationsTab extends EntryEditorTab { | ||
|
|
||
| private final LatexCitationsTabViewModel viewModel; | ||
| private final StackPane searchPane; | ||
| private final ProgressIndicator progressIndicator; | ||
|
|
||
| public LatexCitationsTab(BibDatabaseContext databaseContext, PreferencesService preferencesService, | ||
| TaskExecutor taskExecutor) { | ||
| this.viewModel = new LatexCitationsTabViewModel(databaseContext, preferencesService, taskExecutor); | ||
| this.searchPane = new StackPane(); | ||
| this.progressIndicator = new ProgressIndicator(); | ||
|
|
||
| setText(Localization.lang("LaTeX Citations")); | ||
| setTooltip(new Tooltip(Localization.lang("Search citations for this entry in LaTeX files"))); | ||
| setGraphic(IconTheme.JabRefIcons.LATEX_CITATIONS.getGraphicNode()); | ||
| setSearchPane(); | ||
| } | ||
|
|
||
| private void setSearchPane() { | ||
| progressIndicator.setMaxSize(100, 100); | ||
| searchPane.getStyleClass().add("related-articles-tab"); | ||
|
|
||
| setContent(searchPane); | ||
|
|
||
| EasyBind.subscribe(viewModel.statusProperty(), status -> { | ||
| switch (status) { | ||
| case IN_PROGRESS: | ||
| searchPane.getChildren().setAll(progressIndicator); | ||
| break; | ||
| case CITATIONS_FOUND: | ||
| searchPane.getChildren().setAll(getCitationsPane()); | ||
| break; | ||
| case NO_RESULTS: | ||
| searchPane.getChildren().setAll(getNotFoundPane()); | ||
| break; | ||
| case ERROR: | ||
| searchPane.getChildren().setAll(getErrorPane()); | ||
| break; | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| private ScrollPane getCitationsPane() { | ||
| Text titleText = new Text(Localization.lang("Citations found")); | ||
| titleText.getStyleClass().add("recommendation-heading"); | ||
|
|
||
| VBox citationsBox = new VBox(20, titleText); | ||
| Path basePath = viewModel.directoryProperty().get(); | ||
| citationsBox.getChildren().addAll(viewModel.getCitationList().stream().map( | ||
| citation -> citation.getDisplayGraphic(basePath, Optional.empty())).collect(Collectors.toList())); | ||
|
|
||
| ScrollPane citationsPane = new ScrollPane(); | ||
| citationsPane.setContent(citationsBox); | ||
|
|
||
| return citationsPane; | ||
| } | ||
|
|
||
| private ScrollPane getNotFoundPane() { | ||
| Text notFoundTitleText = new Text(Localization.lang("No citations found")); | ||
| notFoundTitleText.getStyleClass().add("recommendation-heading"); | ||
|
|
||
| Text notFoundText = new Text(Localization.lang("No LaTeX files containing this entry were found.")); | ||
| notFoundText.setStyle("-fx-font-size: 110%"); | ||
|
|
||
| Text notFoundAdviceText = new Text(Localization.lang( | ||
| "You can set the LaTeX file directory in the 'Library properties' dialog.")); | ||
| notFoundAdviceText.setStyle("-fx-font-weight: bold;"); | ||
|
|
||
| VBox notFoundBox = new VBox(20, notFoundTitleText, notFoundText, notFoundAdviceText); | ||
| ScrollPane notFoundPane = new ScrollPane(); | ||
| notFoundPane.setContent(notFoundBox); | ||
|
|
||
| return notFoundPane; | ||
| } | ||
|
|
||
| private ScrollPane getErrorPane() { | ||
| Text errorTitleText = new Text(Localization.lang("Error")); | ||
| errorTitleText.setStyle("-fx-fill: -fx-accent;"); | ||
| errorTitleText.getStyleClass().add("recommendation-heading"); | ||
|
|
||
| Text errorMessageText = new Text(viewModel.searchErrorProperty().get()); | ||
| errorMessageText.setStyle("-fx-font-family: monospace;-fx-font-size: 120%;"); | ||
|
|
||
| VBox errorBox = new VBox(20, errorTitleText, errorMessageText); | ||
| ScrollPane errorPane = new ScrollPane(); | ||
| errorPane.setContent(errorBox); | ||
|
|
||
| return errorPane; | ||
| } | ||
|
|
||
| @Override | ||
| protected void bindToEntry(BibEntry entry) { | ||
| viewModel.init(entry); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean shouldShow(BibEntry entry) { | ||
| return viewModel.shouldShow(); | ||
| } | ||
| } | ||
134 changes: 134 additions & 0 deletions
134
src/main/java/org/jabref/gui/entryeditor/LatexCitationsTabViewModel.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| package org.jabref.gui.entryeditor; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import java.util.concurrent.Future; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import javafx.beans.property.ObjectProperty; | ||
| import javafx.beans.property.ReadOnlyListWrapper; | ||
| import javafx.beans.property.SimpleObjectProperty; | ||
| import javafx.beans.property.SimpleStringProperty; | ||
| import javafx.beans.property.StringProperty; | ||
| import javafx.collections.FXCollections; | ||
| import javafx.collections.ObservableList; | ||
|
|
||
| import org.jabref.gui.AbstractViewModel; | ||
| import org.jabref.gui.texparser.CitationViewModel; | ||
| import org.jabref.gui.util.BackgroundTask; | ||
| import org.jabref.gui.util.TaskExecutor; | ||
| import org.jabref.logic.l10n.Localization; | ||
| import org.jabref.logic.texparser.DefaultTexParser; | ||
| import org.jabref.model.database.BibDatabaseContext; | ||
| import org.jabref.model.entry.BibEntry; | ||
| import org.jabref.model.texparser.TexParserResult; | ||
| import org.jabref.preferences.PreferencesService; | ||
|
|
||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class LatexCitationsTabViewModel extends AbstractViewModel { | ||
|
|
||
| enum Status { | ||
| IN_PROGRESS, | ||
| CITATIONS_FOUND, | ||
| NO_RESULTS, | ||
| ERROR | ||
| } | ||
|
|
||
| private static final Logger LOGGER = LoggerFactory.getLogger(LatexCitationsTabViewModel.class); | ||
| private static final String TEX_EXT = ".tex"; | ||
| private final BibDatabaseContext databaseContext; | ||
| private final PreferencesService preferencesService; | ||
| private final TaskExecutor taskExecutor; | ||
| private final ObjectProperty<Path> directory; | ||
| private final ObservableList<CitationViewModel> citationList; | ||
| private final ObjectProperty<Status> status; | ||
| private final StringProperty searchError; | ||
| private Future<?> searchTask; | ||
|
|
||
| public LatexCitationsTabViewModel(BibDatabaseContext databaseContext, PreferencesService preferencesService, | ||
| TaskExecutor taskExecutor) { | ||
| this.databaseContext = databaseContext; | ||
| this.preferencesService = preferencesService; | ||
| this.taskExecutor = taskExecutor; | ||
| this.directory = new SimpleObjectProperty<>(null); | ||
| this.citationList = FXCollections.observableArrayList(); | ||
| this.status = new SimpleObjectProperty<>(Status.IN_PROGRESS); | ||
| this.searchError = new SimpleStringProperty(""); | ||
| } | ||
|
|
||
| public void init(BibEntry entry) { | ||
| cancelSearch(); | ||
|
|
||
| Optional<String> citeKey = entry.getCiteKeyOptional(); | ||
| if (citeKey.isPresent()) { | ||
| startSearch(citeKey.get()); | ||
| } else { | ||
| searchError.set(Localization.lang("Selected entry does not have an associated BibTeX key.")); | ||
| status.set(Status.ERROR); | ||
| } | ||
| } | ||
|
|
||
| public ObjectProperty<Path> directoryProperty() { | ||
| return directory; | ||
| } | ||
|
|
||
| public ObservableList<CitationViewModel> getCitationList() { | ||
| return new ReadOnlyListWrapper<>(citationList); | ||
| } | ||
|
|
||
| public ObjectProperty<Status> statusProperty() { | ||
| return status; | ||
| } | ||
|
|
||
| public StringProperty searchErrorProperty() { | ||
| return searchError; | ||
| } | ||
|
|
||
| private void startSearch(String citeKey) { | ||
| searchTask = BackgroundTask.wrap(() -> searchAndParse(citeKey)) | ||
| .onRunning(() -> status.set(Status.IN_PROGRESS)) | ||
| .onSuccess(status::set) | ||
| .onFailure(error -> { | ||
| searchError.set(String.format("%s%n%n%s", error.getMessage(), error.getCause())); | ||
| status.set(Status.ERROR); | ||
| }) | ||
| .executeWith(taskExecutor); | ||
| } | ||
|
|
||
| private void cancelSearch() { | ||
| if (searchTask == null || searchTask.isCancelled() || searchTask.isDone()) { | ||
| return; | ||
| } | ||
|
|
||
| status.set(Status.IN_PROGRESS); | ||
| searchTask.cancel(true); | ||
davidemdot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| private Status searchAndParse(String citeKey) throws IOException { | ||
| directory.set(databaseContext.getMetaData().getLaTexFileDirectory(preferencesService.getUser()) | ||
| .orElseGet(preferencesService::getWorkingDir)); | ||
| List<Path> texFiles; | ||
| try (Stream<Path> filesStream = Files.walk(directory.get())) { | ||
| texFiles = filesStream.filter(path -> path.toFile().isFile() && path.toString().endsWith(TEX_EXT)) | ||
| .collect(Collectors.toList()); | ||
| } catch (IOException e) { | ||
| LOGGER.error("Error searching files", e); | ||
| throw new IOException("Error searching files", e); | ||
| } | ||
|
|
||
| TexParserResult texParserResult = new DefaultTexParser().parse(citeKey, texFiles); | ||
| citationList.setAll(texParserResult.getCitations().values().stream().map(CitationViewModel::new).collect(Collectors.toList())); | ||
|
|
||
| return citationList.isEmpty() ? Status.NO_RESULTS : Status.CITATIONS_FOUND; | ||
| } | ||
|
|
||
| public boolean shouldShow() { | ||
| return preferencesService.getEntryEditorPreferences().shouldShowLatexCitationsTab(); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.