Skip to content

Commit 714e3ba

Browse files
Added warning label that allows user to jump to already existing entry (#13390)
* Added warning label that allows user to jump to already existing entry * removed comment and changed hashmap definition * pulled from main and updated CHANGELOG.md * removed line 'requires jbibtex;' from the end of module-info.java * shifted most code to viewmodel from view, removed unused initializeCreateEntry function * removing and updating some logic. the functionality requested should now be functional * removing some existing code and replacing it with validation logic. also added a new key in jabref_en.properties * warning now displays if entry present in any active library. removed commented code and unused variables. * changed return type of checkDOI function for handling null values safely. * duplicate checks now happen in currently active library only. solved tooltip issue. * validation badge now works as intended. adding padding to textfield hyperlink * rectified checkstyle error
1 parent 9656cf1 commit 714e3ba

File tree

6 files changed

+91
-8
lines changed

6 files changed

+91
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
1313

1414
- 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)
1515
- We distribute arm64 images for Linux. [#10842](https://github.com/JabRef/jabref/issues/10842)
16+
- When adding an entry to a library, a warning is displayed if said entry already exists in an active library. [#13261](https://github.com/JabRef/jabref/issues/13261)
1617
- We added the field `monthfiled` to the default list of fields to resolve BibTeX-Strings for [#13375](https://github.com/JabRef/jabref/issues/13375)
1718
- We added a new ID based fetcher for [EuropePMC](https://europepmc.org/). [#13389](https://github.com/JabRef/jabref/pull/13389)
1819
- We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187)

jabgui/src/main/java/org/jabref/gui/newentry/NewEntryView.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
import javafx.scene.control.Button;
1111
import javafx.scene.control.ButtonType;
1212
import javafx.scene.control.ComboBox;
13+
import javafx.scene.control.Hyperlink;
1314
import javafx.scene.control.Label;
1415
import javafx.scene.control.RadioButton;
1516
import javafx.scene.control.Tab;
1617
import javafx.scene.control.TabPane;
1718
import javafx.scene.control.TextArea;
1819
import javafx.scene.control.TextField;
20+
import javafx.scene.control.TextInputControl;
1921
import javafx.scene.control.TitledPane;
2022
import javafx.scene.control.ToggleGroup;
2123
import javafx.scene.control.Tooltip;
@@ -27,6 +29,7 @@
2729
import org.jabref.gui.DialogService;
2830
import org.jabref.gui.LibraryTab;
2931
import org.jabref.gui.StateManager;
32+
import org.jabref.gui.fieldeditors.EditorValidator;
3033
import org.jabref.gui.preferences.GuiPreferences;
3134
import org.jabref.gui.search.SearchType;
3235
import org.jabref.gui.util.BaseDialog;
@@ -104,6 +107,8 @@ public class NewEntryView extends BaseDialog<BibEntry> {
104107
@FXML private TilePane entryCustom;
105108

106109
@FXML private TextField idText;
110+
@FXML private Tooltip idTextTooltip;
111+
@FXML private Hyperlink idJumpLink;
107112
@FXML private RadioButton idLookupGuess;
108113
@FXML private RadioButton idLookupSpecify;
109114
@FXML private ComboBox<IdBasedFetcher> idFetcher;
@@ -260,7 +265,6 @@ private void initializeLookupIdentifier() {
260265
// method (each automatically independently, or all through the same fetcher).
261266
idText.setPromptText(Localization.lang("Enter the reference identifier to search for."));
262267
idText.textProperty().bindBidirectional(viewModel.idTextProperty());
263-
final String clipboardText = ClipBoardManager.getContents().trim();
264268

265269
ToggleGroup toggleGroup = new ToggleGroup();
266270
idLookupGuess.setToggleGroup(toggleGroup);
@@ -272,9 +276,19 @@ private void initializeLookupIdentifier() {
272276
idLookupSpecify.selectedProperty().set(true);
273277
}
274278

279+
viewModel.populateDOICache();
280+
275281
// [impl->req~newentry.clipboard.autofocus~1]
276282
Optional<Identifier> validClipboardId = extractValidIdentifierFromClipboard();
277283
if (validClipboardId.isPresent()) {
284+
viewModel.duplicateDoiValidatorStatus().validProperty().addListener((_, _, isValid) -> {
285+
if (isValid) {
286+
Tooltip.install(idText, idTextTooltip);
287+
} else {
288+
Tooltip.uninstall(idText, idTextTooltip);
289+
}
290+
});
291+
278292
idText.setText(ClipBoardManager.getContents().trim());
279293
idText.selectAll();
280294

@@ -301,8 +315,16 @@ private void initializeLookupIdentifier() {
301315
idFetcher.setValue(initialFetcher);
302316
idFetcher.setOnAction(_ -> preferences.setLatestIdFetcher(idFetcher.getValue().getName()));
303317

318+
idJumpLink.visibleProperty().bind(viewModel.duplicateDoiValidatorStatus().validProperty().not());
304319
idErrorInvalidText.visibleProperty().bind(viewModel.idTextValidatorProperty().not());
320+
idErrorInvalidText.managedProperty().bind(viewModel.idTextValidatorProperty().not());
305321
idErrorInvalidFetcher.visibleProperty().bind(idLookupSpecify.selectedProperty().and(viewModel.idFetcherValidatorProperty().not()));
322+
323+
idJumpLink.setOnAction(_ -> libraryTab.showAndEdit(viewModel.getDuplicateEntry()));
324+
325+
TextInputControl textInput = idText;
326+
EditorValidator validator = new EditorValidator(this.guiPreferences);
327+
validator.configureValidation(viewModel.duplicateDoiValidatorStatus(), textInput);
306328
}
307329

308330
private void initializeInterpretCitations() {

jabgui/src/main/java/org/jabref/gui/newentry/NewEntryViewModel.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.jabref.gui.newentry;
22

3+
import java.util.HashMap;
34
import java.util.List;
5+
import java.util.Map;
46
import java.util.Objects;
57
import java.util.Optional;
68

@@ -38,12 +40,17 @@
3840
import org.jabref.logic.importer.plaincitation.RuleBasedPlainCitationParser;
3941
import org.jabref.logic.importer.plaincitation.SeveralPlainCitationParser;
4042
import org.jabref.logic.l10n.Localization;
43+
import org.jabref.logic.layout.LayoutFormatter;
44+
import org.jabref.logic.layout.format.DOIStrip;
45+
import org.jabref.model.database.BibDatabaseContext;
4146
import org.jabref.model.entry.BibEntry;
47+
import org.jabref.model.entry.field.StandardField;
4248
import org.jabref.model.strings.StringUtil;
4349
import org.jabref.model.util.FileUpdateMonitor;
4450

4551
import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator;
4652
import de.saxsys.mvvmfx.utils.validation.ValidationMessage;
53+
import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
4754
import de.saxsys.mvvmfx.utils.validation.Validator;
4855
import org.slf4j.Logger;
4956
import org.slf4j.LoggerFactory;
@@ -65,6 +72,7 @@ public class NewEntryViewModel {
6572

6673
private final StringProperty idText;
6774
private final Validator idTextValidator;
75+
private final Validator duplicateDoiValidator;
6876
private final ListProperty<IdBasedFetcher> idFetchers;
6977
private final ObjectProperty<IdBasedFetcher> idFetcher;
7078
private final Validator idFetcherValidator;
@@ -79,6 +87,8 @@ public class NewEntryViewModel {
7987
private final StringProperty bibtexText;
8088
private final Validator bibtexTextValidator;
8189
private Task<Optional<List<BibEntry>>> bibtexWorker;
90+
private final Map<String, BibEntry> doiCache;
91+
private BibEntry duplicateEntry;
8292

8393
public NewEntryViewModel(GuiPreferences preferences,
8494
LibraryTab libraryTab,
@@ -97,12 +107,16 @@ public NewEntryViewModel(GuiPreferences preferences,
97107

98108
executing = new SimpleBooleanProperty(false);
99109
executedSuccessfully = new SimpleBooleanProperty(false);
110+
doiCache = new HashMap<>();
100111

101112
idText = new SimpleStringProperty();
102113
idTextValidator = new FunctionBasedValidator<>(
103114
idText,
104115
StringUtil::isNotBlank,
105116
ValidationMessage.error(Localization.lang("You must specify an identifier.")));
117+
duplicateDoiValidator = new FunctionBasedValidator<>(
118+
idText,
119+
input -> checkDOI(input).orElse(null));
106120
idFetchers = new SimpleListProperty<>(FXCollections.observableArrayList());
107121
idFetchers.addAll(WebFetchers.getIdBasedFetchers(preferences.getImportFormatPreferences(), preferences.getImporterPreferences()));
108122
idFetcher = new SimpleObjectProperty<>();
@@ -130,6 +144,41 @@ public NewEntryViewModel(GuiPreferences preferences,
130144
bibtexWorker = null;
131145
}
132146

147+
public void populateDOICache() {
148+
doiCache.clear();
149+
Optional<BibDatabaseContext> activeDatabase = stateManager.getActiveDatabase();
150+
151+
activeDatabase.map(BibDatabaseContext::getEntries)
152+
.ifPresent(entries -> {
153+
entries.forEach(entry -> {
154+
entry.getField(StandardField.DOI)
155+
.ifPresent(doi -> {
156+
doiCache.put(doi, entry);
157+
});
158+
});
159+
});
160+
}
161+
162+
public Optional<ValidationMessage> checkDOI(String doiInput) {
163+
if (doiInput == null || doiInput.isBlank()) {
164+
return Optional.empty();
165+
}
166+
167+
LayoutFormatter doiStrip = new DOIStrip();
168+
String normalized = doiStrip.format(doiInput.toLowerCase());
169+
170+
if (doiCache.containsKey(normalized)) {
171+
duplicateEntry = doiCache.get(normalized);
172+
return Optional.of(ValidationMessage.warning(Localization.lang("Entry already exists in a library")));
173+
}
174+
175+
return Optional.empty();
176+
}
177+
178+
public BibEntry getDuplicateEntry() {
179+
return duplicateEntry;
180+
}
181+
133182
public ReadOnlyBooleanProperty executingProperty() {
134183
return executing;
135184
}
@@ -146,6 +195,10 @@ public ReadOnlyBooleanProperty idTextValidatorProperty() {
146195
return idTextValidator.getValidationStatus().validProperty();
147196
}
148197

198+
public ValidationStatus duplicateDoiValidatorStatus() {
199+
return duplicateDoiValidator.getValidationStatus();
200+
}
201+
149202
public ListProperty<IdBasedFetcher> idFetchersProperty() {
150203
return idFetchers;
151204
}

jabgui/src/main/resources/org/jabref/gui/newentry/NewEntry.fxml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<?import javafx.scene.control.ButtonType?>
55
<?import javafx.scene.control.ComboBox?>
66
<?import javafx.scene.control.DialogPane?>
7+
<?import javafx.scene.control.Hyperlink?>
78
<?import javafx.scene.control.Label?>
89
<?import javafx.scene.control.RadioButton?>
910
<?import javafx.scene.control.Tab?>
@@ -16,6 +17,7 @@
1617
<?import javafx.scene.layout.TilePane?>
1718
<?import javafx.scene.layout.VBox?>
1819
<?import javafx.scene.text.Font?>
20+
<?import javafx.scene.layout.StackPane?>
1921
<DialogPane xmlns:fx="http://javafx.com/fxml/1" prefWidth="600" xmlns="http://javafx.com/javafx/8.0.171"
2022
fx:controller="org.jabref.gui.newentry.NewEntryView">
2123
<buttonTypes>
@@ -58,11 +60,14 @@
5860
</Label>
5961
<HBox alignment="CENTER_LEFT" spacing="10.0">
6062
<Label text="%Identifier"/>
61-
<TextField fx:id="idText" prefHeight="30.0" HBox.hgrow="ALWAYS">
62-
<tooltip>
63-
<Tooltip text="%Specify the source identifier to look up."/>
64-
</tooltip>
65-
</TextField>
63+
<StackPane HBox.hgrow="ALWAYS">
64+
<TextField fx:id="idText" prefHeight="30.0" HBox.hgrow="ALWAYS">
65+
<tooltip>
66+
<Tooltip fx:id="idTextTooltip" text="%Specify the source identifier to look up."/>
67+
</tooltip>
68+
</TextField>
69+
<Hyperlink fx:id="idJumpLink" StackPane.alignment="CENTER_RIGHT" text="%Jump to entry" visible="false" style="-fx-padding: 0 15 0 0;"/>
70+
</StackPane>
6671
</HBox>
6772
<VBox spacing="5.0">
6873
<RadioButton fx:id="idLookupGuess" text="%Automatically determine identifier type">

jablib/src/main/java/org/jabref/logic/database/DuplicateCheck.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ public DuplicateCheck(BibEntryTypesManager entryTypesManager) {
7676

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

8383
private static boolean haveDifferentEntryType(final BibEntry one, final BibEntry two) {

jablib/src/main/resources/l10n/JabRef_en.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,7 @@ Enter\ identifier...=Enter identifier...
29222922
Enter\ identifier=Enter identifier
29232923
Enter\ plain\ citations\ to\ parse,\ separated\ by\ blank\ lines.=Enter plain citations to parse, separated by blank lines.
29242924
Enter\ the\ reference\ identifier\ to\ search\ for.=Enter the reference identifier to search for.
2925+
Entry\ already\ exists\ in\ a\ library=Entry already exists in a library
29252926
Failed\ to\ interpret\ citations.\nThe\ following\ error\ was\ encountered\:\n%0=Failed to interpret citations.\nThe following error was encountered:\n%0
29262927
Failed\ to\ interpret\ citations=Failed to interpret citations
29272928
Failed\ to\ lookup\ identifier=Failed to lookup identifier
@@ -2936,6 +2937,7 @@ Interpret\ citations...=Interpret citations...
29362937
Interpret\ citations=Interpret citations
29372938
Invalid\ result=Invalid result
29382939
Invalid\ result\ returned=Invalid result returned
2940+
Jump\ to\ entry=Jump to entry
29392941
New\ Entry=New Entry
29402942
Other\ types=Other types
29412943
Parser=Parser

0 commit comments

Comments
 (0)