-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5137 from davidemdot/latexintegration-entryeditortab
Add LaTeX citations tab to the entry editor
- Loading branch information
Showing
29 changed files
with
568 additions
and
243 deletions.
There are no files selected for viewing
This file contains 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 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 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 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 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 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); | ||
} | ||
|
||
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 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 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.