Skip to content

Added warning label that allows user to jump to already existing entry #13390

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

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
c345312
Added warning label that allows user to jump to already existing entry
jayvardhanghildiyal Jun 21, 2025
8070987
Merge branch 'main' into fix-for-issue-13261
jayvardhanghildiyal Jun 21, 2025
46f52ec
removed comment and changed hashmap definition
jayvardhanghildiyal Jun 21, 2025
5bafc59
Merge branch 'fix-for-issue-13261' of https://github.com/jayvardhangh…
jayvardhanghildiyal Jun 21, 2025
f453a05
pulled from main and updated CHANGELOG.md
jayvardhanghildiyal Jun 21, 2025
7ef3dc9
removed line 'requires jbibtex;' from the end of module-info.java
jayvardhanghildiyal Jun 21, 2025
ddff1b2
shifted most code to viewmodel from view, removed unused initializeCr…
jayvardhanghildiyal Jun 22, 2025
e6b23f4
Merge branch 'main' into fix-for-issue-13261
jayvardhanghildiyal Jun 22, 2025
4d0fa79
Merge remote-tracking branch 'upstream' into fix-for-issue-13261
jayvardhanghildiyal Jun 23, 2025
619458b
removing and updating some logic. the functionality requested should …
jayvardhanghildiyal Jun 23, 2025
d6cacca
Merge branch 'fix-for-issue-13261' of https://github.com/jayvardhangh…
jayvardhanghildiyal Jun 23, 2025
3fee7ee
removing some existing code and replacing it with validation logic. a…
jayvardhanghildiyal Jun 25, 2025
6cba540
warning now displays if entry present in any active library. removed …
jayvardhanghildiyal Jun 26, 2025
c844bbd
changed return type of checkDOI function for handling null values saf…
jayvardhanghildiyal Jun 26, 2025
87ee01c
duplicate checks now happen in currently active library only. solved …
jayvardhanghildiyal Jun 29, 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 @@ -13,6 +13,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv

- We introduced a settings parameter to manage citations' relations local storage time-to-live with a default value set to 30 days. [#11189](https://github.com/JabRef/jabref/issues/11189)
- We distribute arm64 images for Linux. [#10842](https://github.com/JabRef/jabref/issues/10842)
- When adding a duplicate entry, display warning label that allows user to jump to it instead. [#13261](https://github.com/JabRef/jabref/issues/13261)
- We added the field `monthfiled` to the default list of fields to resolve BibTeX-Strings for [#13375](https://github.com/JabRef/jabref/issues/13375)
- We added a new ID based fetcher for [EuropePMC](https://europepmc.org/). [#13389](https://github.com/JabRef/jabref/pull/13389)

Expand Down
19 changes: 18 additions & 1 deletion jabgui/src/main/java/org/jabref/gui/newentry/NewEntryView.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TextInputControl;
import javafx.scene.control.TitledPane;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.Tooltip;
Expand All @@ -27,6 +29,7 @@
import org.jabref.gui.DialogService;
import org.jabref.gui.LibraryTab;
import org.jabref.gui.StateManager;
import org.jabref.gui.fieldeditors.EditorValidator;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.gui.search.SearchType;
import org.jabref.gui.util.BaseDialog;
Expand Down Expand Up @@ -109,6 +112,8 @@ public class NewEntryView extends BaseDialog<BibEntry> {
@FXML private ComboBox<IdBasedFetcher> idFetcher;
@FXML private Label idErrorInvalidText;
@FXML private Label idErrorInvalidFetcher;
@FXML private Label duplicateSelectLabel;
@FXML private Hyperlink duplicateSelectLink;

@FXML private TextArea interpretText;
@FXML private ComboBox<PlainCitationParserChoice> interpretParser;
Expand Down Expand Up @@ -260,7 +265,6 @@ private void initializeLookupIdentifier() {
// method (each automatically independently, or all through the same fetcher).
idText.setPromptText(Localization.lang("Enter the reference identifier to search for."));
idText.textProperty().bindBidirectional(viewModel.idTextProperty());
final String clipboardText = ClipBoardManager.getContents().trim();

ToggleGroup toggleGroup = new ToggleGroup();
idLookupGuess.setToggleGroup(toggleGroup);
Expand All @@ -272,6 +276,8 @@ private void initializeLookupIdentifier() {
idLookupSpecify.selectedProperty().set(true);
}

viewModel.populateDOICache();

// [impl->req~newentry.clipboard.autofocus~1]
Optional<Identifier> validClipboardId = extractValidIdentifierFromClipboard();
if (validClipboardId.isPresent()) {
Expand Down Expand Up @@ -302,7 +308,18 @@ private void initializeLookupIdentifier() {
idFetcher.setOnAction(_ -> preferences.setLatestIdFetcher(idFetcher.getValue().getName()));

idErrorInvalidText.visibleProperty().bind(viewModel.idTextValidatorProperty().not());
idErrorInvalidText.managedProperty().bind(viewModel.idTextValidatorProperty().not());
idErrorInvalidFetcher.visibleProperty().bind(idLookupSpecify.selectedProperty().and(viewModel.idFetcherValidatorProperty().not()));

// duplicateSelectLink.setOnAction(_ -> {
// if (viewModel.duplicateDoiValidatorProperty() != null) {
// libraryTab.showAndEdit(viewModel.getDuplicateEntry());
// }
// });

TextInputControl textInput = idText;
EditorValidator validator = new EditorValidator(this.guiPreferences);
validator.configureValidation(viewModel.duplicateDoiValidatorStatus(), textInput);
}

private void initializeInterpretCitations() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jabref.gui.newentry;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

Expand Down Expand Up @@ -38,12 +40,17 @@
import org.jabref.logic.importer.plaincitation.RuleBasedPlainCitationParser;
import org.jabref.logic.importer.plaincitation.SeveralPlainCitationParser;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.layout.LayoutFormatter;
import org.jabref.logic.layout.format.DOIStrip;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.StandardField;
import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.FileUpdateMonitor;

import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator;
import de.saxsys.mvvmfx.utils.validation.ValidationMessage;
import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
import de.saxsys.mvvmfx.utils.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -65,6 +72,7 @@ public class NewEntryViewModel {

private final StringProperty idText;
private final Validator idTextValidator;
private final Validator duplicateDoiValidator;
private final ListProperty<IdBasedFetcher> idFetchers;
private final ObjectProperty<IdBasedFetcher> idFetcher;
private final Validator idFetcherValidator;
Expand All @@ -79,6 +87,8 @@ public class NewEntryViewModel {
private final StringProperty bibtexText;
private final Validator bibtexTextValidator;
private Task<Optional<List<BibEntry>>> bibtexWorker;
private BibEntry duplicateEntry;
private final Map<String, BibEntry> doiCache;

public NewEntryViewModel(GuiPreferences preferences,
LibraryTab libraryTab,
Expand All @@ -97,12 +107,16 @@ public NewEntryViewModel(GuiPreferences preferences,

executing = new SimpleBooleanProperty(false);
executedSuccessfully = new SimpleBooleanProperty(false);
doiCache = new HashMap<>();

idText = new SimpleStringProperty();
idTextValidator = new FunctionBasedValidator<>(
idText,
StringUtil::isNotBlank,
ValidationMessage.error(Localization.lang("You must specify an identifier.")));
duplicateDoiValidator = new FunctionBasedValidator<>(
idText,
this::checkDOI);
idFetchers = new SimpleListProperty<>(FXCollections.observableArrayList());
idFetchers.addAll(WebFetchers.getIdBasedFetchers(preferences.getImportFormatPreferences(), preferences.getImporterPreferences()));
idFetcher = new SimpleObjectProperty<>();
Expand Down Expand Up @@ -130,6 +144,34 @@ public NewEntryViewModel(GuiPreferences preferences,
bibtexWorker = null;
}

public void populateDOICache() {
doiCache.clear();
Optional<BibDatabaseContext> activeDatabase = stateManager.getActiveDatabase();

activeDatabase.ifPresent(bibDatabaseContext -> bibDatabaseContext.getEntries()
.forEach(entry -> entry.getField(StandardField.DOI).ifPresent(doi -> {
doiCache.put(doi, entry);
})));
}

public ValidationMessage checkDOI(String doiInput) {
if (doiInput == null) {
return null;
}
LayoutFormatter doiStrip = new DOIStrip();
String normalized = doiStrip.format(doiInput.toLowerCase());

if (doiCache.containsKey(normalized)) {
duplicateEntry = doiCache.get(normalized);
return ValidationMessage.warning(Localization.lang("Entry already exists in a library"));
}
return null;
}

// public BibEntry getDuplicateEntry() {
// return duplicateEntry;
// }

public ReadOnlyBooleanProperty executingProperty() {
return executing;
}
Expand All @@ -146,6 +188,10 @@ public ReadOnlyBooleanProperty idTextValidatorProperty() {
return idTextValidator.getValidationStatus().validProperty();
}

public ValidationStatus duplicateDoiValidatorStatus() {
return duplicateDoiValidator.getValidationStatus();
}

public ListProperty<IdBasedFetcher> idFetchersProperty() {
return idFetchers;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<?import javafx.scene.control.ButtonType?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Tab?>
Expand Down Expand Up @@ -88,6 +89,14 @@
<Label fx:id="idErrorInvalidText" text="%You must provide an identifier.">
<font><Font name="System Italic" size="13.0"/></font>
</Label>
<!-- <HBox>-->
<!-- <Label fx:id="duplicateSelectLabel" text="Entry already exists in library.">-->
<!-- <font><Font name="System Italic" size="13.0"/></font>-->
<!-- </Label>-->
<!-- <Hyperlink fx:id="duplicateSelectLink" text=" Jump to entry.">-->
<!-- <font><Font name="System Italic" size="13.0"/></font>-->
<!-- </Hyperlink>-->
<!-- </HBox>-->
<Label fx:id="idErrorInvalidFetcher" text="%You must select an identifier type.">
<font><Font name="System Italic" size="13.0"/></font>
</Label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ public DuplicateCheck(BibEntryTypesManager entryTypesManager) {

private static boolean haveSameIdentifier(final BibEntry one, final BibEntry two) {
return one.getFields().stream()
.filter(field -> field.getProperties().contains(FieldProperty.IDENTIFIER))
.anyMatch(field -> two.getField(field).map(content -> one.getField(field).orElseThrow().equals(content)).orElse(false));
.filter(field -> field.getProperties().contains(FieldProperty.IDENTIFIER))
.anyMatch(field -> two.getField(field).map(content -> one.getField(field).orElseThrow().equals(content)).orElse(false));
}

private static boolean haveDifferentEntryType(final BibEntry one, final BibEntry two) {
Expand Down
1 change: 1 addition & 0 deletions jablib/src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2916,6 +2916,7 @@ Enter\ identifier...=Enter identifier...
Enter\ identifier=Enter identifier
Enter\ plain\ citations\ to\ parse,\ separated\ by\ blank\ lines.=Enter plain citations to parse, separated by blank lines.
Enter\ the\ reference\ identifier\ to\ search\ for.=Enter the reference identifier to search for.
Entry\ already\ exists\ in\ a\ library=Entry already exists in a library
Failed\ to\ interpret\ citations.\nThe\ following\ error\ was\ encountered\:\n%0=Failed to interpret citations.\nThe following error was encountered:\n%0
Failed\ to\ interpret\ citations=Failed to interpret citations
Failed\ to\ lookup\ identifier=Failed to lookup identifier
Expand Down