Skip to content

Add support for loading .blg warnings in Integrity Check Dialog #12866

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
merged 21 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
aab2f21
Add .blg warning support in IntegrityCheckDialog with Browse/Reset an…
wanling0000 Mar 31, 2025
a4b657f
Apply review suggestions
wanling0000 Apr 1, 2025
d1e4eb1
Merge remote-tracking branch 'upstream/main' into feature/11998-blg-i…
wanling0000 Apr 1, 2025
753cadc
Apply changes based on review feedback
wanling0000 Apr 1, 2025
a3b6847
add missing localization key for BibTeX log files
wanling0000 Apr 1, 2025
6760ced
apply OpenRewrite suggestions
wanling0000 Apr 1, 2025
b694915
Fix preferences and Reset logic for .blg file settings
wanling0000 Apr 2, 2025
f86643b
Apply review suggestions
wanling0000 Apr 2, 2025
64301be
Apply review suggestions
wanling0000 Apr 2, 2025
6f2aab3
Fix failing unit tests
wanling0000 Apr 2, 2025
907fb0c
Merge branch 'main' into feature/11998-blg-integrity
wanling0000 Apr 7, 2025
32dd199
Apply review suggestions
wanling0000 Apr 7, 2025
2f5ec93
Apply review suggestions and improve separation of concerns for blg w…
wanling0000 Apr 14, 2025
eb33f20
Merge upstream/main
wanling0000 Apr 14, 2025
05d2cd3
Fix localization key + apply bot suggestions
wanling0000 Apr 14, 2025
f21199c
Apply bot suggestions on fast-fail, fix Rewrite and test failures
wanling0000 Apr 15, 2025
cf93fc1
Remove star imports
wanling0000 Apr 15, 2025
a75431b
Remove unnecessary @NonNull annotations and fix misleading UI warning…
wanling0000 Apr 17, 2025
a629dbb
Apply review suggestions: simplify test and update Javadoc
wanling0000 Apr 18, 2025
b1ae65b
Resolve merge conflict with upstream/main
wanling0000 Apr 18, 2025
19a7c5f
Revert unintended submodule change to csl-styles
wanling0000 Apr 18, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We added a feature for enabling drag-and-drop of files into groups [#12540](https://github.com/JabRef/jabref/issues/12540)
- We added support for reordering keywords via drag and drop, automatic alphabetical ordering, and improved pasting and editing functionalities in the keyword editor. [#10984](https://github.com/JabRef/jabref/issues/10984)
- We added a new functionality where author names having multiple spaces in-between will be considered as separate user block as it does for " and ". [#12701](https://github.com/JabRef/jabref/issues/12701)
- We added support for loading and displaying BibTeX .blg warnings in the Check integrity dialog, with custom path selection and metadata persistence. [#11998](https://github.com/JabRef/jabref/issues/11998)
- We added an option to choose whether to open the file explorer in the files directory or in the last opened directory when attaching files. [#12554](https://github.com/JabRef/jabref/issues/12554)
- We enhanced support for parsing XMP metadata from PDF files. [#12829](https://github.com/JabRef/jabref/issues/12829)
- We added a "Preview" header in the JStyles tab in the "Select style" dialog, to make it consistent with the CSL styles tab. [#12838](https://github.com/JabRef/jabref/pull/12838)
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/org/jabref/gui/integrity/BibLogSettingsPane.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>

<HBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
spacing="10"
alignment="CENTER_LEFT"
fx:controller="org.jabref.gui.integrity.BibLogSettingsPane"
fx:id="bibLogSettingsPane">
<Label text="BibTeX log (.blg) file:"/>
<TextField fx:id="pathField" prefWidth="300"/>
<Button onAction="#onBrowse" text="Browse..."/>
<Button onAction="#onReset" text="Reset"/>
</HBox>
88 changes: 88 additions & 0 deletions src/main/java/org/jabref/gui/integrity/BibLogSettingsPane.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.jabref.gui.integrity;

import java.nio.file.Path;

import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;

import org.jabref.gui.DialogService;
import org.jabref.gui.util.FileDialogConfiguration;
import org.jabref.logic.JabRefException;
import org.jabref.logic.integrity.IntegrityMessage;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.util.StandardFileType;
import org.jabref.model.database.BibDatabaseContext;

import jakarta.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Controller for the .blg file settings panel.
*
* Binds the path text field to the ViewModel,
* and handles browse/reset button actions.
*/
public class BibLogSettingsPane {
private static final Logger LOGGER = LoggerFactory.getLogger(BibLogSettingsPane.class);
@FXML
private TextField pathField;
private BibLogSettingsViewModel viewModel;
@Inject private DialogService dialogService;
private Runnable onBlgPathChanged;

public void initializeViewModel(BibDatabaseContext context, Runnable onBlgPathChanged) throws JabRefException {
this.onBlgPathChanged = onBlgPathChanged;
this.viewModel = new BibLogSettingsViewModel(context.getMetaData(), context.getDatabasePath());
pathField.textProperty().bindBidirectional(viewModel.pathProperty());
viewModel.getBlgWarnings(context);
}

public ObservableList<IntegrityMessage> getBlgWarnings() {
return viewModel.getBlgWarningsObservable();
}

public void refreshWarnings(BibDatabaseContext context) throws JabRefException {
viewModel.getBlgWarnings(context);
}

@FXML
private void onBrowse() {
FileDialogConfiguration fileDialogConfiguration = createBlgFileDialogConfig();
dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(path -> {
viewModel.setBlgFilePath(path);
notifyPathChanged();
});
}

@FXML
private void onReset() {
viewModel.resetBlgFilePath();
notifyPathChanged();
}

private void notifyPathChanged() {
if (onBlgPathChanged != null) {
onBlgPathChanged.run();
}
}

public BibLogSettingsViewModel getViewModel() {
return viewModel;
}

private FileDialogConfiguration createBlgFileDialogConfig() {
Path initialDir = viewModel.getInitialDirectory();
FileDialogConfiguration config = new FileDialogConfiguration.Builder()
.addExtensionFilter(Localization.lang("BibTeX log files"), StandardFileType.BLG)
.withDefaultExtension(Localization.lang("BibTeX log files"), StandardFileType.BLG)
.withInitialDirectory(viewModel.getInitialDirectory())
.build();
return config;
}

public boolean wasBlgFileManuallySelected() {
return viewModel.wasBlgFileManuallySelected();
}
}
129 changes: 129 additions & 0 deletions src/main/java/org/jabref/gui/integrity/BibLogSettingsViewModel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package org.jabref.gui.integrity;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;

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.logic.JabRefException;
import org.jabref.logic.biblog.BibLogPathResolver;
import org.jabref.logic.biblog.BibWarningToIntegrityMessageConverter;
import org.jabref.logic.biblog.BibtexLogParser;
import org.jabref.logic.integrity.IntegrityMessage;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.biblog.BibWarning;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.metadata.MetaData;

/// 1. Connects MetaData with the view.
/// 2. Wraps .blg warnings as IntegrityMessages.
/// 3. Supports file browsing and reset actions.
public class BibLogSettingsViewModel extends AbstractViewModel {
private final ObservableList<IntegrityMessage> blgWarnings = FXCollections.observableArrayList();
private final StringProperty path = new SimpleStringProperty("");
private final MetaData metaData;
private final Optional<Path> bibPath;
private final String user;
private Optional<Path> lastResolvedBlgPath = Optional.empty();
private boolean userManuallySelectedBlgFile = false;

public BibLogSettingsViewModel(MetaData metaData, Optional<Path> bibPath) {
this.metaData = metaData;
this.bibPath = bibPath;
this.user = System.getProperty("user.name");

BibLogPathResolver.resolve(metaData, bibPath, user)
.ifPresent(resolvedPath -> {
this.path.set(resolvedPath.toString());
if (metaData.getBlgFilePath(user).isEmpty()) {
metaData.setBlgFilePath(user, resolvedPath);
this.lastResolvedBlgPath = Optional.of(resolvedPath);
}
});
Comment on lines +42 to +49
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code does not follow the fail-fast principle. It should return early if the condition is not met, instead of nesting logic inside an if statement.

}

/**
* Parses the .blg file (if it exists) into the observable list.
*
* @param databaseContext the current database context used to resolve citation keys in warnings.
* @return An Optional containing the list of integrity messages if the file exists and can be parsed,
* or an empty Optional if the file does not exist.
* @throws JabRefException if the .blg file cannot be parsed or read
*/
public Optional<List<IntegrityMessage>> getBlgWarnings(BibDatabaseContext databaseContext) throws JabRefException {
Optional<Path> resolved = getResolvedBlgPath();
if (resolved.isEmpty()) {
blgWarnings.clear();
return Optional.empty();
}

Path path = resolved.get();

this.lastResolvedBlgPath = Optional.of(path);
try {
BibtexLogParser parser = new BibtexLogParser();
List<BibWarning> warnings = parser.parseBiblog(path);
List<IntegrityMessage> newWarnings = BibWarningToIntegrityMessageConverter.convert(warnings, databaseContext);
blgWarnings.setAll(newWarnings);
return Optional.of(newWarnings);
} catch (IOException e) {
blgWarnings.clear();
throw new JabRefException(
"Failed to parse .blg file",
Localization.lang("Could not read BibTeX log file. Please check the file path and try again."),
e
);
}
}

public ObservableList<IntegrityMessage> getBlgWarningsObservable() {
return blgWarnings;
}

public StringProperty pathProperty() {
return path;
}

public void setBlgFilePath(Path path) {
metaData.setBlgFilePath(user, path);
this.path.set(path.toString());
this.lastResolvedBlgPath = Optional.of(path);
this.userManuallySelectedBlgFile = true;
}

public void resetBlgFilePath() {
metaData.clearBlgFilePath(user);
userManuallySelectedBlgFile = false;
Optional<Path> resolved = BibLogPathResolver.resolve(metaData, bibPath, user);
if (resolved.isEmpty()) {
path.set("");
lastResolvedBlgPath = Optional.empty();
return;
}

Path resolvedPath = resolved.get();
path.set(resolvedPath.toString());
lastResolvedBlgPath = Optional.of(resolvedPath);
}
Comment on lines +101 to +114
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method does not follow the fail-fast principle. It should return early if the condition is not met, instead of nesting logic inside an if statement.


public Optional<Path> getResolvedBlgPath() {
return BibLogPathResolver.resolve(metaData, bibPath, user)
.filter(Files::exists);
}

public Path getInitialDirectory() {
return bibPath.flatMap(path -> Optional.ofNullable(path.getParent()))
.orElse(Path.of(System.getProperty("user.home")));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this cross-platform ("user.home")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not on Windows XP, but this is acceptable: https://stackoverflow.com/q/585534/873282

}

public boolean wasBlgFileManuallySelected() {
return userManuallySelectedBlgFile;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ protected List<IntegrityMessage> call() {
result.addAll(check.checkEntry(entry));
updateProgress(i, entries.size());
}

return result;
}
};
Expand All @@ -78,7 +77,7 @@ protected List<IntegrityMessage> call() {
if (messages.isEmpty()) {
dialogService.notify(Localization.lang("No problems found."));
} else {
dialogService.showCustomDialogAndWait(new IntegrityCheckDialog(messages, tabSupplier.get()));
dialogService.showCustomDialogAndWait(new IntegrityCheckDialog(messages, tabSupplier.get(), dialogService));
}
});
task.setOnFailed(event -> dialogService.showErrorDialogAndWait("Integrity check failed.", task.getException()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonType?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<DialogPane xmlns:fx="http://javafx.com/fxml/1" prefHeight="600.0" prefWidth="700.0"
xmlns="http://javafx.com/javafx/8.0.121" fx:controller="org.jabref.gui.integrity.IntegrityCheckDialog">
<content>
<VBox spacing="4.0">
<VBox fx:id="dialogVBox" spacing="4.0">
<TableView fx:id="messagesTable" prefHeight="550" prefWidth="700.0" VBox.vgrow="ALWAYS" HBox.hgrow="ALWAYS">
<columns>
<TableColumn fx:id="keyColumn" prefWidth="150.0" maxWidth="200" text="%Citation key"/>
Expand Down
Loading
Loading