Skip to content
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

Add LaTeX citations tab to the entry editor #5137

Merged
merged 34 commits into from
Jul 29, 2019
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a13e3b2
Update EntryEditor for using PreferencesService
davidemdot Jul 18, 2019
fedda55
Add LaTeX references tab option to entry editor preferences
davidemdot Jul 18, 2019
4214103
Add getCitationsByKey(BibEntry) method in TexParserResult
davidemdot Jul 18, 2019
4ba7f0d
Add LaTeX references tab to the entry editor
davidemdot Jul 18, 2019
d1fc7b3
Add missing localization keys
davidemdot Jul 19, 2019
145b631
Fix bug related to the display of results
davidemdot Jul 19, 2019
cba1949
Replace Boolean with boolean type in preferences
davidemdot Jul 20, 2019
47deee4
Rename feature-related stuff (references -> citations)
davidemdot Jul 20, 2019
4d7256d
Update CHANGELOG.md
davidemdot Jul 20, 2019
04d1a5f
Improve exception handling and add search cancellation
davidemdot Jul 20, 2019
0d41f30
Update DefaultTexParser for avoiding ClosedByInterruptException when …
davidemdot Jul 20, 2019
0095bed
Update EntryEditor for adding @Inject uses
davidemdot Jul 20, 2019
de0db44
Fix bug in EntryEditor (setOnDragDropped event)
davidemdot Jul 20, 2019
e6722ee
Merge remote-tracking branch 'origin/master' into latexintegration-en…
davidemdot Jul 20, 2019
b1c7cb6
Update logger messages in cancelSearch()
davidemdot Jul 20, 2019
824ba0d
Update LaTeX citations tab for using a enum status property
davidemdot Jul 20, 2019
1fd6d4e
Merge branch 'master' into latexintegration-entryeditortab
davidemdot Jul 24, 2019
ce4f925
Improve performance in the entry editor tab by searching for only the…
davidemdot Jul 24, 2019
00287d8
Add default case to bindToEntry() in LatexCitationsTab
davidemdot Jul 24, 2019
b2c75cb
Update for adding small improvements
davidemdot Jul 25, 2019
2db46d2
Improve performance and exception handling
davidemdot Jul 25, 2019
2b700f1
Update error message for entries without BibTeX key
davidemdot Jul 25, 2019
3fd9c36
Update GUI classes for public access
davidemdot Jul 25, 2019
4c88528
Fix minor issues
davidemdot Jul 26, 2019
0dbd084
Update for improving code
davidemdot Jul 26, 2019
2a3f4ac
Update for adding the last improvements
davidemdot Jul 26, 2019
e4c0e14
Update for code refining
davidemdot Jul 26, 2019
de5d705
Set the search pane in LatexCitationsTab just once
davidemdot Jul 28, 2019
3bb24a6
Update LatexCitationsTabViewModel for avoiding 'orElse(null)'
davidemdot Jul 28, 2019
ee1501e
Update TexParserResult for avoiding 'orElse(null)'
davidemdot Jul 28, 2019
5cc4622
Update DefaultTexParser for explaining when and why it skips the cita…
davidemdot Jul 28, 2019
3d019db
Change toString() methods
davidemdot Jul 28, 2019
7adf03a
Add a new JabRefIcons.LATEX_CITATIONS
davidemdot Jul 28, 2019
34713f5
Fix all issues from reviews of #5137
davidemdot Jul 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- We moved the dropdown menu for selecting the push-application from the toolbar into the external application preferences. [#674](https://github.com/JabRef/jabref/issues/674)
- We removed the alphabetical ordering of the custom tabs and updated the error message when trying to create a general field with a name containing an illegal character. [#5019](https://github.com/JabRef/jabref/issues/5019)
- We added a context menu to the bib(la)tex-source-editor to copy'n'paste. [#5007](https://github.com/JabRef/jabref/pull/5007)
- We added a bibliographic references search, for finding references in several LaTeX files. This tool scans directories and shows which entries are used, how many times and where.
- We added a tool that allows searching for citations in LaTeX files. It scans directories and shows which entries are used, how many times and where.
- We added a 'LaTeX citations' tab to the entry editor, to search for citations to the active entry in the LaTeX file directory. It can be disabled in the preferences dialog.
- We added an option in preferences to allow for integers in field "edition" when running database in bibtex mode. [#4680](https://github.com/JabRef/jabref/issues/4680)


Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/BasePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas

this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs));

this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences(), Globals.getFileUpdateMonitor(), dialogService, externalFileTypes, Globals.TASK_EXECUTOR, Globals.stateManager);
this.entryEditor = new EntryEditor(this, externalFileTypes);

this.preview = new PreviewPanel(getBibDatabaseContext(), this, dialogService, externalFileTypes, Globals.getKeyPrefs(), preferences.getPreviewPreferences());
}
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.css
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,45 @@
.bibtexSourceCodeArea .text {
-fx-fill: -fx-text-background-color;
}

.latex-citations-tab {
-fx-background-color: -fx-control-inner-background;
-fx-padding: 20px;
}

.latex-citations-title-text {
davidemdot marked this conversation as resolved.
Show resolved Hide resolved
-fx-font-size: 140%;
-fx-font-weight: bold;
}

.latex-citations-context-box {
-fx-border-color: grey;
-fx-border-style: dashed;
-fx-border-width: 2px;
-fx-font-size: 110%;
-fx-font-style: italic;
-fx-padding: 15px;
}

.latex-citations-position-text {
-fx-font-family: 'Courier New', Courier, monospace;
}

.latex-citations-not-found-text {
-fx-font-size: 110%;
}

.latex-citations-not-found-advice-text {
-fx-font-weight: bold;
}

.latex-citations-error-title-text {
-fx-font-size: 140%;
-fx-font-weight: bold;
-fx-fill: -fx-accent;
}

.latex-citations-error-text {
-fx-font-family: 'Courier New', Courier, monospace;
-fx-font-size: 120%;
}
146 changes: 76 additions & 70 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ public class EntryEditorPreferences {
private boolean showSourceTabByDefault;
private final KeyBindingRepository keyBindings;
private boolean avoidOverwritingCiteKey;
private final boolean shouldShowLatexCitationsTab;

public EntryEditorPreferences(Map<String, List<String>> entryEditorTabList, LatexFieldFormatterPreferences latexFieldFormatterPreferences, ImportFormatPreferences importFormatPreferences, List<String> customTabFieldNames, boolean shouldShowRecommendationsTab, boolean isMrdlibAccepted, boolean showSourceTabByDefault, BibtexKeyPatternPreferences bibtexKeyPatternPreferences, KeyBindingRepository keyBindings, boolean avoidOverwritingCiteKey) {
public EntryEditorPreferences(Map<String, List<String>> entryEditorTabList, LatexFieldFormatterPreferences latexFieldFormatterPreferences, ImportFormatPreferences importFormatPreferences, List<String> customTabFieldNames, boolean shouldShowRecommendationsTab, boolean isMrdlibAccepted, boolean shouldShowLatexCitationsTab, boolean showSourceTabByDefault, BibtexKeyPatternPreferences bibtexKeyPatternPreferences, KeyBindingRepository keyBindings, boolean avoidOverwritingCiteKey) {
this.entryEditorTabList = entryEditorTabList;
this.latexFieldFormatterPreferences = latexFieldFormatterPreferences;
this.importFormatPreferences = importFormatPreferences;
Expand All @@ -32,6 +33,7 @@ public EntryEditorPreferences(Map<String, List<String>> entryEditorTabList, Late
this.bibtexKeyPatternPreferences = bibtexKeyPatternPreferences;
this.keyBindings = keyBindings;
this.avoidOverwritingCiteKey = avoidOverwritingCiteKey;
this.shouldShowLatexCitationsTab = shouldShowLatexCitationsTab;
}

public Map<String, List<String>> getEntryEditorTabList() {
Expand Down Expand Up @@ -78,6 +80,10 @@ public void setShowSourceTabByDefault(boolean showSourceTabByDefault) {
this.showSourceTabByDefault = showSourceTabByDefault;
}

public boolean shouldShowLatexCitationsTab() {
return shouldShowLatexCitationsTab;
}

public boolean avoidOverwritingCiteKey() {
return avoidOverwritingCiteKey;
}
Expand Down
137 changes: 137 additions & 0 deletions src/main/java/org/jabref/gui/entryeditor/LatexCitationsTab.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.jabref.gui.entryeditor;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.HBox;
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.model.strings.LatexToUnicodeAdapter;
import org.jabref.model.texparser.Citation;
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;
private final ObservableList<VBox> graphicCitationList;

public LatexCitationsTab(BibDatabaseContext databaseContext, PreferencesService preferencesService,
TaskExecutor taskExecutor) {
this.viewModel = new LatexCitationsTabViewModel(databaseContext, preferencesService, taskExecutor);
this.searchPane = new StackPane();
this.progressIndicator = new ProgressIndicator();
this.graphicCitationList = FXCollections.observableArrayList();

setText(Localization.lang("LaTeX Citations"));
setTooltip(new Tooltip(Localization.lang("Search citations for this entry in LaTeX files")));
setGraphic(IconTheme.JabRefIcons.APPLICATION_TEXSTUDIO.getGraphicNode());
davidemdot marked this conversation as resolved.
Show resolved Hide resolved
}

private void setupSearchPane() {
progressIndicator.setMaxSize(100.0, 100.0);
searchPane.getStyleClass().add("latex-citations-tab");

setContent(searchPane);
}

@Override
protected void bindToEntry(BibEntry entry) {
setupSearchPane();
davidemdot marked this conversation as resolved.
Show resolved Hide resolved

EasyBind.subscribe(viewModel.statusProperty(), status -> {
switch (status) {
case IN_PROGRESS:
searchPane.getChildren().setAll(progressIndicator);
break;
case CITATIONS_FOUND:
graphicCitationList.setAll(EasyBind.map(viewModel.getCitationList(), this::citationToGraphic));
searchPane.getChildren().setAll(getCitationsPane());
break;
case NO_RESULTS:
searchPane.getChildren().setAll(getNotFoundPane());
break;
case ERROR:
searchPane.getChildren().setAll(getErrorPane());
break;
default:
break;
}
});

viewModel.init(entry);
}

private VBox citationToGraphic(Citation citation) {
HBox contextBox = new HBox(new Text(LatexToUnicodeAdapter.format(citation.getLineText())));
contextBox.getStyleClass().add("latex-citations-context-box");

Text positionText = new Text(String.format("%n%s (%s:%s-%s)", citation.getPath().toAbsolutePath(),
citation.getLine(), citation.getColStart(), citation.getColEnd()));
positionText.getStyleClass().add("latex-citations-position-text");

return new VBox(contextBox, positionText);
}

private ScrollPane getCitationsPane() {
davidemdot marked this conversation as resolved.
Show resolved Hide resolved
Text titleText = new Text(Localization.lang("Citations found"));
titleText.getStyleClass().add("latex-citations-title-text");

VBox citationsBox = new VBox(20.0, titleText);
citationsBox.getChildren().addAll(graphicCitationList);

ScrollPane citationsPane = new ScrollPane();
citationsPane.setContent(citationsBox);

return citationsPane;
}

private ScrollPane getNotFoundPane() {
Text notFoundTitleText = new Text(Localization.lang("No citations found"));
notFoundTitleText.getStyleClass().add("latex-citations-title-text");

Text notFoundText = new Text(Localization.lang("No LaTeX files containing this entry were found."));
notFoundText.getStyleClass().add("latex-citations-not-found-text");

Text notFoundAdviceText = new Text(Localization.lang(
"You can set the LaTeX file directory in the 'Library properties' dialog."));
notFoundAdviceText.getStyleClass().add("latex-citations-not-found-advice-text");

VBox notFoundBox = new VBox(20.0, notFoundTitleText, notFoundText, notFoundAdviceText);
ScrollPane notFoundPane = new ScrollPane();
notFoundPane.setContent(notFoundBox);

return notFoundPane;
}

private ScrollPane getErrorPane() {
Text errorTitleText = new Text(Localization.lang("Error"));
errorTitleText.getStyleClass().add("latex-citations-error-title-text");

Text errorMessageText = new Text(viewModel.searchErrorProperty().get());
errorMessageText.getStyleClass().add("latex-citations-error-text");

VBox errorBox = new VBox(20.0, errorTitleText, errorMessageText);
ScrollPane errorPane = new ScrollPane();
errorPane.setContent(errorBox);

return errorPane;
}

@Override
public boolean shouldShow(BibEntry entry) {
return viewModel.shouldShow();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
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.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.Citation;
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 StringProperty entryKey;
private final ObservableList<Citation> 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.entryKey = new SimpleStringProperty(null);
this.citationList = FXCollections.observableArrayList();
this.status = new SimpleObjectProperty<>(Status.IN_PROGRESS);
this.searchError = new SimpleStringProperty(null);
}

public void init(BibEntry entry) {
cancelSearch();

if (!entry.getCiteKeyOptional().isPresent()) {
searchError.set(Localization.lang("Selected entry does not have an associated BibTeX key."));
status.set(Status.ERROR);
return;
}

this.entryKey.set(entry.getCiteKeyOptional().orElse(null));
startSearch();
}

public ObservableList<Citation> getCitationList() {
return new ReadOnlyListWrapper<>(citationList);
}

public ObjectProperty<Status> statusProperty() {
return status;
}

public StringProperty searchErrorProperty() {
return searchError;
}

private void startSearch() {
searchTask = BackgroundTask.wrap(this::searchAndParse)
.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;
}

searchTask.cancel(true);
davidemdot marked this conversation as resolved.
Show resolved Hide resolved

if (searchTask.isCancelled()) {
LOGGER.debug("Last search has been cancelled");
} else {
LOGGER.warn("Could not cancel last search");
}
}

private Status searchAndParse() throws IOException {
Path directory = databaseContext.getMetaData().getLaTexFileDirectory(preferencesService.getUser())
.orElseGet(preferencesService::getWorkingDir);

List<Path> texFiles;
try (Stream<Path> filesStream = Files.walk(directory)) {
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(Optional.of(entryKey.get()), texFiles);
citationList.setAll(texParserResult.getCitations().values());

return citationList.isEmpty() ? Status.NO_RESULTS : Status.CITATIONS_FOUND;
}

public boolean shouldShow() {
return preferencesService.getEntryEditorPreferences().shouldShowLatexCitationsTab();
}
}
Loading