diff --git a/CHANGELOG.md b/CHANGELOG.md index 6863e32cdf7..ca7162119e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We made the font size in the entry editor and group panel customizable by "Menu and label font size". [#3034](https://github.com/JabRef/jabref/issues/3034) - If fetched article is already in database, then the entry merge dialog is shown. - An error message is now displayed if you try to create a group containing the keyword separator or if there is already a group with the same name. [#3075](https://github.com/JabRef/jabref/issues/3075) and [#1495](https://github.com/JabRef/jabref/issues/1495) +- Integrity warnings are now directly displayed in the entry editor. ### Fixed @@ -26,6 +27,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where DEL, Ctrl+C, Ctrl+V and Ctrl+A in the search field triggered corresponding actions in the main table [#3067](https://github.com/JabRef/jabref/issues/3067) - We fixed an issue where JabRef freezed when editing an assigned file in the `General`-Tab [#2930, comment](https://github.com/JabRef/jabref/issues/2930#issuecomment-311050976) - We fixed an issue where a file could not be assigned to an existing entry via the entry context menu action `Attach file` [#3080](https://github.com/JabRef/jabref/issues/3080) + ### Removed diff --git a/build.gradle b/build.gradle index f3f7b8c4126..96268da5bbf 100644 --- a/build.gradle +++ b/build.gradle @@ -103,6 +103,7 @@ dependencies { compile 'de.codecentric.centerdevice:javafxsvg:1.2.1' compile 'org.controlsfx:controlsfx:8.40.13' compile 'org.fxmisc.easybind:easybind:1.0.3' + compile 'de.saxsys:mvvmfx-validation:1.6.0' compile 'org.fxmisc.flowless:flowless:0.5.2' compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' diff --git a/external-libraries.txt b/external-libraries.txt index 02e257a40bc..6a2a5d15ba3 100644 --- a/external-libraries.txt +++ b/external-libraries.txt @@ -224,6 +224,11 @@ Project: javafxsvg URL: https://github.com/codecentric/javafxsvg License: BSD 3-Clause +Id: de.saxsys:mvvmfx +Project: mvvm(fx) +URL: https://github.com/sialcasa/mvvmFX +License: Apache-2.0 + Id: com.github.tomtung Project: latex2unicode URL: https://github.com/tomtung/latex2unicode diff --git a/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java index 7f458cc5310..f249aa1c37a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/AbstractEditorViewModel.java @@ -13,8 +13,14 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.BindingsHelper; +import org.jabref.logic.integrity.FieldCheckers; +import org.jabref.logic.integrity.ValueChecker; import org.jabref.model.entry.BibEntry; +import de.saxsys.mvvmfx.utils.validation.CompositeValidator; +import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.Validator; import org.controlsfx.control.textfield.AutoCompletionBinding; public class AbstractEditorViewModel extends AbstractViewModel { @@ -22,11 +28,23 @@ public class AbstractEditorViewModel extends AbstractViewModel { protected StringProperty text = new SimpleStringProperty(""); protected BibEntry entry; private final AutoCompleteSuggestionProvider suggestionProvider; + private final CompositeValidator fieldValidator; private ObjectBinding fieldBinding; - public AbstractEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { + public AbstractEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { this.fieldName = fieldName; this.suggestionProvider = suggestionProvider; + + this.fieldValidator = new CompositeValidator(); + for (ValueChecker checker : fieldCheckers.getForField(fieldName)) { + FunctionBasedValidator validator = new FunctionBasedValidator<>(text, value -> + checker.checkValue(value).map(ValidationMessage::warning).orElse(null)); + fieldValidator.addValidators(validator); + } + } + + public Validator getFieldValidator() { + return fieldValidator; } public StringProperty textProperty() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java b/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java index 65a1dbcce55..78bff7f6bc4 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/DateEditor.java @@ -9,6 +9,7 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.util.ControlHelper; import org.jabref.gui.util.component.TemporalAccessorPicker; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; public class DateEditor extends HBox implements FieldEditorFX { @@ -16,8 +17,8 @@ public class DateEditor extends HBox implements FieldEditorFX { @FXML private DateEditorViewModel viewModel; @FXML private TemporalAccessorPicker datePicker; - public DateEditor(String fieldName, DateTimeFormatter dateFormatter, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new DateEditorViewModel(fieldName, suggestionProvider, dateFormatter); + public DateEditor(String fieldName, DateTimeFormatter dateFormatter, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new DateEditorViewModel(fieldName, suggestionProvider, dateFormatter, fieldCheckers); ControlHelper.loadFXMLForControl(this); diff --git a/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java index 6ea9f8d2237..dc68f1d5d15 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/DateEditorViewModel.java @@ -7,14 +7,15 @@ import javafx.util.StringConverter; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.Date; import org.jabref.model.strings.StringUtil; public class DateEditorViewModel extends AbstractEditorViewModel { private final DateTimeFormatter dateFormatter; - public DateEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DateTimeFormatter dateFormatter) { - super(fieldName, suggestionProvider); + public DateEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DateTimeFormatter dateFormatter, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.dateFormatter = dateFormatter; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java index 118430fea4b..e3c7ccfd40a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/EditorTypeEditorViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import com.google.common.collect.BiMap; @@ -10,8 +11,8 @@ public class EditorTypeEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(7); - public EditorTypeEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public EditorTypeEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); itemMap.put("editor", Localization.lang("Editor")); itemMap.put("compiler", Localization.lang("Compiler")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java index 089a71ab3f2..20083ef3680 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java +++ b/src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java @@ -10,6 +10,7 @@ import org.jabref.gui.autocompleter.ContentSelectorSuggestionProvider; import org.jabref.gui.autocompleter.SuggestionProviders; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationPreferences; import org.jabref.model.database.BibDatabaseContext; @@ -30,46 +31,48 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu AutoCompleteSuggestionProvider suggestionProvider = getSuggestionProvider(fieldName, suggestionProviders, databaseContext.getMetaData()); + FieldCheckers fieldCheckers = new FieldCheckers(databaseContext, preferences.getFileDirectoryPreferences()); + if (Globals.prefs.getTimestampPreferences().getTimestampField().equals(fieldName) || fieldExtras.contains(FieldProperty.DATE)) { if (fieldExtras.contains(FieldProperty.ISO_DATE)) { - return new DateEditor(fieldName, DateTimeFormatter.ofPattern("[uuuu][-MM][-dd]"), suggestionProvider); + return new DateEditor(fieldName, DateTimeFormatter.ofPattern("[uuuu][-MM][-dd]"), suggestionProvider, fieldCheckers); } else { - return new DateEditor(fieldName, DateTimeFormatter.ofPattern(Globals.prefs.getTimestampPreferences().getTimestampFormat()), suggestionProvider); + return new DateEditor(fieldName, DateTimeFormatter.ofPattern(Globals.prefs.getTimestampPreferences().getTimestampFormat()), suggestionProvider, fieldCheckers); } } else if (fieldExtras.contains(FieldProperty.EXTERNAL)) { - return new UrlEditor(fieldName, dialogService, suggestionProvider); + return new UrlEditor(fieldName, dialogService, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.JOURNAL_NAME)) { - return new JournalEditor(fieldName, journalAbbreviationLoader, journalAbbreviationPreferences, suggestionProvider); + return new JournalEditor(fieldName, journalAbbreviationLoader, journalAbbreviationPreferences, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.DOI) || fieldExtras.contains(FieldProperty.EPRINT) || fieldExtras.contains(FieldProperty.ISBN)) { - return new IdentifierEditor(fieldName, taskExecutor, dialogService, suggestionProvider); + return new IdentifierEditor(fieldName, taskExecutor, dialogService, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.OWNER)) { - return new OwnerEditor(fieldName, preferences, suggestionProvider); + return new OwnerEditor(fieldName, preferences, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.FILE_EDITOR)) { - return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider); + return new LinkedFilesEditor(fieldName, dialogService, databaseContext, taskExecutor, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.YES_NO)) { - return new OptionEditor<>(fieldName, new YesNoEditorViewModel(fieldName, suggestionProvider)); + return new OptionEditor<>(fieldName, new YesNoEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.MONTH)) { - return new OptionEditor<>(fieldName, new MonthEditorViewModel(fieldName, suggestionProvider, databaseContext.getMode())); + return new OptionEditor<>(fieldName, new MonthEditorViewModel(fieldName, suggestionProvider, databaseContext.getMode(), fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.GENDER)) { - return new OptionEditor<>(fieldName, new GenderEditorViewModel(fieldName, suggestionProvider)); + return new OptionEditor<>(fieldName, new GenderEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.EDITOR_TYPE)) { - return new OptionEditor<>(fieldName, new EditorTypeEditorViewModel(fieldName, suggestionProvider)); + return new OptionEditor<>(fieldName, new EditorTypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.PAGINATION)) { - return new OptionEditor<>(fieldName, new PaginationEditorViewModel(fieldName, suggestionProvider)); + return new OptionEditor<>(fieldName, new PaginationEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else if (fieldExtras.contains(FieldProperty.TYPE)) { if ("patent".equalsIgnoreCase(entryType)) { - return new OptionEditor<>(fieldName, new PatentTypeEditorViewModel(fieldName, suggestionProvider)); + return new OptionEditor<>(fieldName, new PatentTypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } else { - return new OptionEditor<>(fieldName, new TypeEditorViewModel(fieldName, suggestionProvider)); + return new OptionEditor<>(fieldName, new TypeEditorViewModel(fieldName, suggestionProvider, fieldCheckers)); } } else if (fieldExtras.contains(FieldProperty.SINGLE_ENTRY_LINK) || fieldExtras.contains(FieldProperty.MULTIPLE_ENTRY_LINK)) { - return new LinkedEntriesEditor(fieldName, databaseContext, suggestionProvider); + return new LinkedEntriesEditor(fieldName, databaseContext, suggestionProvider, fieldCheckers); } else if (fieldExtras.contains(FieldProperty.PERSON_NAMES)) { - return new PersonsEditor(fieldName, suggestionProvider, preferences.getAutoCompletePreferences()); + return new PersonsEditor(fieldName, suggestionProvider, preferences.getAutoCompletePreferences(), fieldCheckers); } // default - return new SimpleEditor(fieldName, suggestionProvider); + return new SimpleEditor(fieldName, suggestionProvider, fieldCheckers); } @SuppressWarnings("unchecked") diff --git a/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java index 8678807cb0b..a1ec99fed4f 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/GenderEditorViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import com.google.common.collect.BiMap; @@ -10,8 +11,8 @@ public class GenderEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(7); - public GenderEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public GenderEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); itemMap.put("sf", Localization.lang("Female name")); itemMap.put("sm", Localization.lang("Male name")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java index 49640668bae..d99389be2e6 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java @@ -17,10 +17,13 @@ import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.gui.util.ControlHelper; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + public class IdentifierEditor extends HBox implements FieldEditorFX { @FXML private IdentifierEditorViewModel viewModel; @@ -29,8 +32,8 @@ public class IdentifierEditor extends HBox implements FieldEditorFX { @FXML private Button lookupIdentifierButton; private Optional entry; - public IdentifierEditor(String fieldName, TaskExecutor taskExecutor, DialogService dialogService, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new IdentifierEditorViewModel(fieldName, suggestionProvider, taskExecutor, dialogService); + public IdentifierEditor(String fieldName, TaskExecutor taskExecutor, DialogService dialogService, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new IdentifierEditorViewModel(fieldName, suggestionProvider, taskExecutor, dialogService, fieldCheckers); ControlHelper.loadFXMLForControl(this); @@ -47,6 +50,9 @@ public IdentifierEditor(String fieldName, TaskExecutor taskExecutor, DialogServi } menuItems.addAll(EditorMenus.getDefaultMenu(textArea)); textArea.addToContextMenu(menuItems); + + ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea); } public IdentifierEditorViewModel getViewModel() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java index 850d041c827..f714e0764b4 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModel.java @@ -16,6 +16,7 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.importer.WebFetchers; import org.jabref.logic.importer.util.IdentifierParser; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; @@ -31,8 +32,8 @@ public class IdentifierEditorViewModel extends AbstractEditorViewModel { private TaskExecutor taskExecutor; private DialogService dialogService; - public IdentifierEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, TaskExecutor taskExecutor, DialogService dialogService) { - super(fieldName, suggestionProvider); + public IdentifierEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, TaskExecutor taskExecutor, DialogService dialogService, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.taskExecutor = taskExecutor; this.dialogService = dialogService; diff --git a/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java b/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java index 27a6c823e38..71eb2bacbc6 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java @@ -11,18 +11,21 @@ import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; import org.jabref.gui.util.ControlHelper; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationPreferences; import org.jabref.model.entry.BibEntry; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + public class JournalEditor extends HBox implements FieldEditorFX { @FXML private JournalEditorViewModel viewModel; @FXML private EditorTextArea textArea; private Optional entry; - public JournalEditor(String fieldName, JournalAbbreviationLoader journalAbbreviationLoader, JournalAbbreviationPreferences journalAbbreviationPreferences, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new JournalEditorViewModel(fieldName, suggestionProvider, journalAbbreviationLoader, journalAbbreviationPreferences); + public JournalEditor(String fieldName, JournalAbbreviationLoader journalAbbreviationLoader, JournalAbbreviationPreferences journalAbbreviationPreferences, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new JournalEditorViewModel(fieldName, suggestionProvider, journalAbbreviationLoader, journalAbbreviationPreferences, fieldCheckers); ControlHelper.loadFXMLForControl(this); @@ -30,6 +33,9 @@ public JournalEditor(String fieldName, JournalAbbreviationLoader journalAbbrevia textArea.addToContextMenu(EditorMenus.getDefaultMenu(textArea)); AutoCompletionTextInputBinding.autoComplete(textArea, viewModel::complete); + + ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea); } public JournalEditorViewModel getViewModel() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java index 278f6c955f2..e59d1305efc 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/JournalEditorViewModel.java @@ -3,6 +3,7 @@ import java.util.Optional; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationPreferences; import org.jabref.logic.journals.JournalAbbreviationRepository; @@ -12,8 +13,8 @@ public class JournalEditorViewModel extends AbstractEditorViewModel { private final JournalAbbreviationLoader journalAbbreviationLoader; private final JournalAbbreviationPreferences journalAbbreviationPreferences; - public JournalEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, JournalAbbreviationLoader journalAbbreviationLoader, JournalAbbreviationPreferences journalAbbreviationPreferences) { - super(fieldName, suggestionProvider); + public JournalEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, JournalAbbreviationLoader journalAbbreviationLoader, JournalAbbreviationPreferences journalAbbreviationPreferences, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.journalAbbreviationLoader = journalAbbreviationLoader; this.journalAbbreviationPreferences = journalAbbreviationPreferences; diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java index f90dc27a89e..6c8a940ca90 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditor.java @@ -8,6 +8,7 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.util.ControlHelper; import org.jabref.gui.util.component.TagBar; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.ParsedEntryLink; @@ -17,8 +18,8 @@ public class LinkedEntriesEditor extends HBox implements FieldEditorFX { @FXML private LinkedEntriesEditorViewModel viewModel; @FXML private TagBar linkedEntriesBar; - public LinkedEntriesEditor(String fieldName, BibDatabaseContext databaseContext, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new LinkedEntriesEditorViewModel(fieldName, suggestionProvider, databaseContext); + public LinkedEntriesEditor(String fieldName, BibDatabaseContext databaseContext, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new LinkedEntriesEditorViewModel(fieldName, suggestionProvider, databaseContext, fieldCheckers); ControlHelper.loadFXMLForControl(this); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java index dce4a28b009..bf9e889de6c 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedEntriesEditorViewModel.java @@ -7,6 +7,7 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.util.BindingsHelper; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.EntryLinkList; import org.jabref.model.entry.ParsedEntryLink; @@ -16,8 +17,8 @@ public class LinkedEntriesEditorViewModel extends AbstractEditorViewModel { private final BibDatabaseContext databaseContext; private final ListProperty linkedEntries; - public LinkedEntriesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, BibDatabaseContext databaseContext) { - super(fieldName, suggestionProvider); + public LinkedEntriesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, BibDatabaseContext databaseContext, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.databaseContext = databaseContext; linkedEntries = new SimpleListProperty<>(FXCollections.observableArrayList()); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 9e83cf2a34e..7a2675f165e 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -27,6 +27,7 @@ import org.jabref.gui.util.ControlHelper; import org.jabref.gui.util.TaskExecutor; import org.jabref.gui.util.ViewModelListCellFactory; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -39,8 +40,8 @@ public class LinkedFilesEditor extends HBox implements FieldEditorFX { @FXML private final LinkedFilesEditorViewModel viewModel; @FXML private ListView listView; - public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor); + public LinkedFilesEditor(String fieldName, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new LinkedFilesEditorViewModel(fieldName, suggestionProvider, dialogService, databaseContext, taskExecutor, fieldCheckers); ControlHelper.loadFXMLForControl(this); diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java index 87a944f430b..b18680cb654 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java @@ -30,6 +30,7 @@ import org.jabref.gui.util.FileDialogConfiguration; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.importer.FulltextFetchers; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLDownload; import org.jabref.logic.util.OS; @@ -57,8 +58,8 @@ public class LinkedFilesEditorViewModel extends AbstractEditorViewModel { private final BibDatabaseContext databaseContext; private final TaskExecutor taskExecutor; - public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor) { - super(fieldName, suggestionProvider); + public LinkedFilesEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, BibDatabaseContext databaseContext, TaskExecutor taskExecutor, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.dialogService = dialogService; this.databaseContext = databaseContext; diff --git a/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java index 8fd185db2f3..e3ae0b22920 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/MapBasedEditorViewModel.java @@ -6,6 +6,7 @@ import javafx.util.StringConverter; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import com.google.common.collect.BiMap; @@ -14,8 +15,8 @@ */ public abstract class MapBasedEditorViewModel extends OptionEditorViewModel { - public MapBasedEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public MapBasedEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); } protected abstract BiMap getItemMap(); diff --git a/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java index 49c3c1592e5..16cadcd7d4f 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/MonthEditorViewModel.java @@ -6,6 +6,7 @@ import javafx.util.StringConverter; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.Month; import org.jabref.model.strings.StringUtil; @@ -13,8 +14,8 @@ public class MonthEditorViewModel extends OptionEditorViewModel { private BibDatabaseMode databaseMode; - public MonthEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, BibDatabaseMode databaseMode) { - super(fieldName, suggestionProvider); + public MonthEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.databaseMode = databaseMode; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java index 4bafb4de7c8..f642144d9b8 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OptionEditorViewModel.java @@ -5,11 +5,12 @@ import javafx.util.StringConverter; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; public abstract class OptionEditorViewModel extends AbstractEditorViewModel { - public OptionEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public OptionEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); } public abstract StringConverter getStringConverter(); diff --git a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java index ea869e1cf9e..c1558ed8899 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditor.java @@ -7,20 +7,26 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.util.ControlHelper; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + public class OwnerEditor extends HBox implements FieldEditorFX { @FXML private OwnerEditorViewModel viewModel; @FXML private EditorTextArea textArea; - public OwnerEditor(String fieldName, JabRefPreferences preferences, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new OwnerEditorViewModel(fieldName, suggestionProvider, preferences); + public OwnerEditor(String fieldName, JabRefPreferences preferences, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new OwnerEditorViewModel(fieldName, suggestionProvider, preferences, fieldCheckers); ControlHelper.loadFXMLForControl(this); textArea.textProperty().bindBidirectional(viewModel.textProperty()); + + ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea); } public OwnerEditorViewModel getViewModel() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java index 7c2bef29fae..3b071dffb1b 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/OwnerEditorViewModel.java @@ -1,13 +1,14 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.preferences.JabRefPreferences; public class OwnerEditorViewModel extends AbstractEditorViewModel { private final JabRefPreferences preferences; - public OwnerEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, JabRefPreferences preferences) { - super(fieldName, suggestionProvider); + public OwnerEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, JabRefPreferences preferences, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.preferences = preferences; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java index 2b51e82266e..b9e269131d2 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PaginationEditorViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import com.google.common.collect.BiMap; @@ -10,8 +11,8 @@ public class PaginationEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(7); - public PaginationEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public PaginationEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); itemMap.put("page", Localization.lang("Page")); itemMap.put("column", Localization.lang("Column")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java index 5523efe3cb6..d8cdd5d3dd1 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PatentTypeEditorViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import com.google.common.collect.BiMap; @@ -10,8 +11,8 @@ public class PatentTypeEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(12); - public PatentTypeEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public PatentTypeEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); itemMap.put("patent", Localization.lang("Patent")); itemMap.put("patentde", Localization.lang("German patent")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java index 36dd9ed425c..f55b88b4f34 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java @@ -9,14 +9,17 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + public class PersonsEditor extends HBox implements FieldEditorFX { @FXML private final PersonsEditorViewModel viewModel; - public PersonsEditor(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, AutoCompletePreferences autoCompletePreferences) { - this.viewModel = new PersonsEditorViewModel(fieldName, suggestionProvider, autoCompletePreferences); + public PersonsEditor(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, AutoCompletePreferences autoCompletePreferences, FieldCheckers fieldCheckers) { + this.viewModel = new PersonsEditorViewModel(fieldName, suggestionProvider, autoCompletePreferences, fieldCheckers); EditorTextArea textArea = new EditorTextArea(); HBox.setHgrow(textArea, Priority.ALWAYS); @@ -25,6 +28,9 @@ public PersonsEditor(String fieldName, AutoCompleteSuggestionProvider suggest this.getChildren().add(textArea); AutoCompletionTextInputBinding.autoComplete(textArea, viewModel::complete, viewModel.getAutoCompletionConverter(), viewModel.getAutoCompletionStrategy()); + + ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea); } @Override diff --git a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java index c41ac32773e..d85910c2953 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/PersonsEditorViewModel.java @@ -9,6 +9,7 @@ import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionStrategy; import org.jabref.gui.autocompleter.PersonNameStringConverter; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.Author; import org.controlsfx.control.textfield.AutoCompletionBinding; @@ -17,8 +18,8 @@ public class PersonsEditorViewModel extends AbstractEditorViewModel { private final AutoCompletePreferences preferences; - public PersonsEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, AutoCompletePreferences preferences) { - super(fieldName, suggestionProvider); + public PersonsEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, AutoCompletePreferences preferences, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.preferences = preferences; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java index 261e8a43501..168a3819a7a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java @@ -9,14 +9,17 @@ import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding; import org.jabref.gui.autocompleter.ContentSelectorSuggestionProvider; import org.jabref.gui.fieldeditors.contextmenu.EditorMenus; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + public class SimpleEditor extends HBox implements FieldEditorFX { @FXML private final SimpleEditorViewModel viewModel; - public SimpleEditor(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new SimpleEditorViewModel(fieldName, suggestionProvider); + public SimpleEditor(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new SimpleEditorViewModel(fieldName, suggestionProvider, fieldCheckers); EditorTextArea textArea = new EditorTextArea(); HBox.setHgrow(textArea, Priority.ALWAYS); @@ -29,6 +32,9 @@ public SimpleEditor(String fieldName, AutoCompleteSuggestionProvider suggesti // If content selector values are present, then we want to show the auto complete suggestions immediately on focus autoCompleter.setShowOnFocus(true); } + + ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea); } @Override diff --git a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java index 1cc61e93ab7..3a006fa460d 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/SimpleEditorViewModel.java @@ -3,11 +3,12 @@ import org.jabref.gui.autocompleter.AppendWordsStrategy; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.autocompleter.AutoCompletionStrategy; +import org.jabref.logic.integrity.FieldCheckers; public class SimpleEditorViewModel extends AbstractEditorViewModel { - public SimpleEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public SimpleEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); } public AutoCompletionStrategy getAutoCompletionStrategy() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java index 0ad32035de1..e13e4200323 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/TypeEditorViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import com.google.common.collect.BiMap; @@ -10,8 +11,8 @@ public class TypeEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(8); - public TypeEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public TypeEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); itemMap.put("mathesis", Localization.lang("Master's thesis")); itemMap.put("phdthesis", Localization.lang("PhD thesis")); diff --git a/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java b/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java index 6bffe03deee..7a621b5325a 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/UrlEditor.java @@ -8,19 +8,25 @@ import org.jabref.gui.DialogService; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.util.ControlHelper; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.model.entry.BibEntry; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; + public class UrlEditor extends HBox implements FieldEditorFX { @FXML private UrlEditorViewModel viewModel; @FXML private EditorTextArea textArea; - public UrlEditor(String fieldName, DialogService dialogService, AutoCompleteSuggestionProvider suggestionProvider) { - this.viewModel = new UrlEditorViewModel(fieldName, suggestionProvider, dialogService); + public UrlEditor(String fieldName, DialogService dialogService, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + this.viewModel = new UrlEditorViewModel(fieldName, suggestionProvider, dialogService, fieldCheckers); ControlHelper.loadFXMLForControl(this); textArea.textProperty().bindBidirectional(viewModel.textProperty()); + + ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); + validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea); } public UrlEditorViewModel getViewModel() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java index 051a5e34b56..f370a1a89ad 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/UrlEditorViewModel.java @@ -8,6 +8,7 @@ import org.jabref.gui.DialogService; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; import org.jabref.gui.desktop.JabRefDesktop; +import org.jabref.logic.integrity.FieldCheckers; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLUtil; import org.jabref.model.strings.StringUtil; @@ -18,8 +19,8 @@ public class UrlEditorViewModel extends AbstractEditorViewModel { private DialogService dialogService; private BooleanProperty validUrlIsNotPresent = new SimpleBooleanProperty(true); - public UrlEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService) { - super(fieldName, suggestionProvider); + public UrlEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, DialogService dialogService, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); this.dialogService = dialogService; validUrlIsNotPresent.bind( diff --git a/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java index 7cad3e7e356..fcf9c59e40b 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/YesNoEditorViewModel.java @@ -1,6 +1,7 @@ package org.jabref.gui.fieldeditors; import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider; +import org.jabref.logic.integrity.FieldCheckers; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; @@ -9,8 +10,8 @@ public class YesNoEditorViewModel extends MapBasedEditorViewModel { private BiMap itemMap = HashBiMap.create(2); - public YesNoEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider) { - super(fieldName, suggestionProvider); + public YesNoEditorViewModel(String fieldName, AutoCompleteSuggestionProvider suggestionProvider, FieldCheckers fieldCheckers) { + super(fieldName, suggestionProvider, fieldCheckers); itemMap.put("yes", "Yes"); itemMap.put("no", "No"); diff --git a/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java b/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java index 9203d9e4bba..f8eff670c11 100644 --- a/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java +++ b/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java @@ -3,11 +3,16 @@ import java.util.Optional; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; public class AbbreviationChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (value.contains(".")) { return Optional.of(Localization.lang("abbreviation detected")); } diff --git a/src/main/java/org/jabref/logic/integrity/BooktitleChecker.java b/src/main/java/org/jabref/logic/integrity/BooktitleChecker.java index ea781bf20b1..3ed8b36a6e7 100644 --- a/src/main/java/org/jabref/logic/integrity/BooktitleChecker.java +++ b/src/main/java/org/jabref/logic/integrity/BooktitleChecker.java @@ -4,11 +4,16 @@ import java.util.Optional; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; public class BooktitleChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (value.toLowerCase(Locale.ENGLISH).endsWith("conference on")) { return Optional.of(Localization.lang("booktitle ends with 'conference on'")); } diff --git a/src/main/java/org/jabref/logic/integrity/BracketChecker.java b/src/main/java/org/jabref/logic/integrity/BracketChecker.java index d5215d9a94b..bff56b03770 100644 --- a/src/main/java/org/jabref/logic/integrity/BracketChecker.java +++ b/src/main/java/org/jabref/logic/integrity/BracketChecker.java @@ -3,11 +3,16 @@ import java.util.Optional; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; public class BracketChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + // metaphor: integer-based stack (push + / pop -) int counter = 0; for (char a : value.trim().toCharArray()) { diff --git a/src/main/java/org/jabref/logic/integrity/DOIValidityChecker.java b/src/main/java/org/jabref/logic/integrity/DOIValidityChecker.java index e2f2f069303..09c144a087f 100644 --- a/src/main/java/org/jabref/logic/integrity/DOIValidityChecker.java +++ b/src/main/java/org/jabref/logic/integrity/DOIValidityChecker.java @@ -4,11 +4,16 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.identifier.DOI; +import org.jabref.model.strings.StringUtil; public class DOIValidityChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (DOI.isValid(value)) { return Optional.empty(); } else { diff --git a/src/main/java/org/jabref/logic/integrity/EditionChecker.java b/src/main/java/org/jabref/logic/integrity/EditionChecker.java index 87f968346a2..54a1869bfe2 100644 --- a/src/main/java/org/jabref/logic/integrity/EditionChecker.java +++ b/src/main/java/org/jabref/logic/integrity/EditionChecker.java @@ -7,6 +7,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.strings.StringUtil; public class EditionChecker implements ValueChecker { @@ -33,6 +34,10 @@ public EditionChecker(BibDatabaseContext bibDatabaseContext) { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + //biblatex if (bibDatabaseContextEdition.isBiblatexMode() && !ONLY_NUMERALS_OR_LITERALS.test(value.trim())) { return Optional.of(Localization.lang("should contain an integer or a literal")); diff --git a/src/main/java/org/jabref/logic/integrity/FieldCheckers.java b/src/main/java/org/jabref/logic/integrity/FieldCheckers.java index f809d535cf2..5439e09b7ef 100644 --- a/src/main/java/org/jabref/logic/integrity/FieldCheckers.java +++ b/src/main/java/org/jabref/logic/integrity/FieldCheckers.java @@ -1,5 +1,6 @@ package org.jabref.logic.integrity; +import java.util.Collection; import java.util.List; import java.util.stream.Collectors; @@ -13,14 +14,10 @@ public class FieldCheckers { - private FieldCheckers() { - } + private Multimap fieldChecker; - static List getAll(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) { - return getAllMap(databaseContext, fileDirectoryPreferences) - .entries().stream() - .map(pair -> new FieldChecker(pair.getKey(), pair.getValue())) - .collect(Collectors.toList()); + public FieldCheckers(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) { + fieldChecker = getAllMap(databaseContext, fileDirectoryPreferences); } private static Multimap getAllMap(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) { @@ -52,4 +49,17 @@ private static Multimap getAllMap(BibDatabaseContext datab return fieldCheckers; } + + public List getAll() { + return fieldChecker + .entries() + .stream() + .map(pair -> new FieldChecker(pair.getKey(), pair.getValue())) + .collect(Collectors.toList()); + } + + public Collection getForField(String field) { + return fieldChecker + .get(field); + } } diff --git a/src/main/java/org/jabref/logic/integrity/FileChecker.java b/src/main/java/org/jabref/logic/integrity/FileChecker.java index 56b9f89ca17..f631230922b 100644 --- a/src/main/java/org/jabref/logic/integrity/FileChecker.java +++ b/src/main/java/org/jabref/logic/integrity/FileChecker.java @@ -11,6 +11,7 @@ import org.jabref.model.entry.FileFieldParser; import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FileDirectoryPreferences; +import org.jabref.model.strings.StringUtil; public class FileChecker implements ValueChecker { @@ -25,6 +26,10 @@ public FileChecker(BibDatabaseContext context, FileDirectoryPreferences fileDire @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + List linkedFiles = FileFieldParser.parse(value).stream() .filter(file -> !file.isOnlineLink()) .collect(Collectors.toList()); diff --git a/src/main/java/org/jabref/logic/integrity/HowPublishedChecker.java b/src/main/java/org/jabref/logic/integrity/HowPublishedChecker.java index 2286caba87a..1406e3641a5 100644 --- a/src/main/java/org/jabref/logic/integrity/HowPublishedChecker.java +++ b/src/main/java/org/jabref/logic/integrity/HowPublishedChecker.java @@ -7,6 +7,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.strings.StringUtil; public class HowPublishedChecker implements ValueChecker { @@ -27,6 +28,10 @@ public HowPublishedChecker(BibDatabaseContext databaseContext) { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + //BibTeX if (!databaseContext.isBiblatexMode() && !FIRST_LETTER_CAPITALIZED.test(value.trim())) { return Optional.of(Localization.lang("should have the first letter capitalized")); diff --git a/src/main/java/org/jabref/logic/integrity/ISBNChecker.java b/src/main/java/org/jabref/logic/integrity/ISBNChecker.java index a8aa29054c0..c774dc9148a 100644 --- a/src/main/java/org/jabref/logic/integrity/ISBNChecker.java +++ b/src/main/java/org/jabref/logic/integrity/ISBNChecker.java @@ -4,11 +4,16 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.identifier.ISBN; +import org.jabref.model.strings.StringUtil; public class ISBNChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + // Check that the ISBN is on the correct form ISBN isbn = new ISBN(value); diff --git a/src/main/java/org/jabref/logic/integrity/ISSNChecker.java b/src/main/java/org/jabref/logic/integrity/ISSNChecker.java index 11dae320d84..23502ec9e8a 100644 --- a/src/main/java/org/jabref/logic/integrity/ISSNChecker.java +++ b/src/main/java/org/jabref/logic/integrity/ISSNChecker.java @@ -4,11 +4,16 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.identifier.ISSN; +import org.jabref.model.strings.StringUtil; public class ISSNChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + // Check that the ISSN is on the correct form String issnString = value.trim(); diff --git a/src/main/java/org/jabref/logic/integrity/IntegrityCheck.java b/src/main/java/org/jabref/logic/integrity/IntegrityCheck.java index 62e49aa6232..8407864502e 100644 --- a/src/main/java/org/jabref/logic/integrity/IntegrityCheck.java +++ b/src/main/java/org/jabref/logic/integrity/IntegrityCheck.java @@ -46,7 +46,8 @@ private List checkBibtexEntry(BibEntry entry) { return result; } - for (FieldChecker checker : FieldCheckers.getAll(bibDatabaseContext, fileDirectoryPreferences)) { + FieldCheckers fieldCheckers = new FieldCheckers(bibDatabaseContext, fileDirectoryPreferences); + for (FieldChecker checker : fieldCheckers.getAll()) { result.addAll(checker.check(entry)); } diff --git a/src/main/java/org/jabref/logic/integrity/MonthChecker.java b/src/main/java/org/jabref/logic/integrity/MonthChecker.java index 3bb5a9c5b22..402fbf65f66 100644 --- a/src/main/java/org/jabref/logic/integrity/MonthChecker.java +++ b/src/main/java/org/jabref/logic/integrity/MonthChecker.java @@ -7,6 +7,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.strings.StringUtil; public class MonthChecker implements ValueChecker { @@ -33,6 +34,10 @@ public MonthChecker(BibDatabaseContext bibDatabaseContext) { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + //biblatex if (bibDatabaseContextMonth.isBiblatexMode() && !(ONLY_AN_INTEGER.test(value.trim()) || MONTH_NORMALIZED.test(value.trim()))) { diff --git a/src/main/java/org/jabref/logic/integrity/NoteChecker.java b/src/main/java/org/jabref/logic/integrity/NoteChecker.java index a12236b1bd6..e6cdc6e6ba3 100644 --- a/src/main/java/org/jabref/logic/integrity/NoteChecker.java +++ b/src/main/java/org/jabref/logic/integrity/NoteChecker.java @@ -7,6 +7,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.strings.StringUtil; public class NoteChecker implements ValueChecker { @@ -27,6 +28,10 @@ public NoteChecker(BibDatabaseContext bibDatabaseContext) { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + //BibTeX if (!bibDatabaseContextEdition.isBiblatexMode() && !FIRST_LETTER_CAPITALIZED.test(value.trim())) { return Optional.of(Localization.lang("should have the first letter capitalized")); diff --git a/src/main/java/org/jabref/logic/integrity/PagesChecker.java b/src/main/java/org/jabref/logic/integrity/PagesChecker.java index ae0cdbba36e..0040afd2f2a 100644 --- a/src/main/java/org/jabref/logic/integrity/PagesChecker.java +++ b/src/main/java/org/jabref/logic/integrity/PagesChecker.java @@ -6,6 +6,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.strings.StringUtil; public class PagesChecker implements ValueChecker { @@ -52,6 +53,10 @@ public PagesChecker(BibDatabaseContext databaseContext) { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (!isValidPageNumber.test(value.trim())) { return Optional.of(Localization.lang("should contain a valid page number range")); } diff --git a/src/main/java/org/jabref/logic/integrity/PersonNamesChecker.java b/src/main/java/org/jabref/logic/integrity/PersonNamesChecker.java index 572070ae975..33ee505871a 100644 --- a/src/main/java/org/jabref/logic/integrity/PersonNamesChecker.java +++ b/src/main/java/org/jabref/logic/integrity/PersonNamesChecker.java @@ -5,11 +5,16 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.AuthorList; +import org.jabref.model.strings.StringUtil; public class PersonNamesChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + String valueTrimmedAndLowerCase = value.trim().toLowerCase(Locale.ROOT); if (valueTrimmedAndLowerCase.startsWith("and ") || valueTrimmedAndLowerCase.startsWith(",")) { return Optional.of(Localization.lang("should start with a name")); diff --git a/src/main/java/org/jabref/logic/integrity/TitleChecker.java b/src/main/java/org/jabref/logic/integrity/TitleChecker.java index a321a2b7e91..c2725949d24 100644 --- a/src/main/java/org/jabref/logic/integrity/TitleChecker.java +++ b/src/main/java/org/jabref/logic/integrity/TitleChecker.java @@ -7,6 +7,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.strings.StringUtil; public class TitleChecker implements ValueChecker { @@ -28,6 +29,10 @@ public TitleChecker(BibDatabaseContext databaseContext) { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (databaseContext.isBiblatexMode()) { return Optional.empty(); } diff --git a/src/main/java/org/jabref/logic/integrity/UrlChecker.java b/src/main/java/org/jabref/logic/integrity/UrlChecker.java index 7ce1bc219dd..8d99968ac96 100644 --- a/src/main/java/org/jabref/logic/integrity/UrlChecker.java +++ b/src/main/java/org/jabref/logic/integrity/UrlChecker.java @@ -3,11 +3,16 @@ import java.util.Optional; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; public class UrlChecker implements ValueChecker { @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (!value.contains("://")) { return Optional.of(Localization.lang("should contain a protocol") + ": http[s]://, file://, ftp://, ..."); } diff --git a/src/main/java/org/jabref/logic/integrity/YearChecker.java b/src/main/java/org/jabref/logic/integrity/YearChecker.java index 4a7fdb9cbb7..b137c0ea407 100644 --- a/src/main/java/org/jabref/logic/integrity/YearChecker.java +++ b/src/main/java/org/jabref/logic/integrity/YearChecker.java @@ -5,6 +5,7 @@ import java.util.regex.Pattern; import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; public class YearChecker implements ValueChecker { @@ -22,6 +23,10 @@ public class YearChecker implements ValueChecker { */ @Override public Optional checkValue(String value) { + if (StringUtil.isBlank(value)) { + return Optional.empty(); + } + if (!CONTAINS_FOUR_DIGIT.test(value.trim())) { return Optional.of(Localization.lang("should contain a four digit number")); } diff --git a/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java index 92c3e63eefa..d681344d9b0 100644 --- a/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java +++ b/src/test/java/org/jabref/gui/fieldeditors/IdentifierEditorViewModelTest.java @@ -3,6 +3,7 @@ import org.jabref.gui.DialogService; import org.jabref.gui.autocompleter.WordSuggestionProvider; import org.jabref.gui.util.CurrentThreadTaskExecutor; +import org.jabref.logic.integrity.FieldCheckers; import org.junit.Before; import org.junit.Test; @@ -16,7 +17,7 @@ public class IdentifierEditorViewModelTest { @Before public void setUp() throws Exception { - viewModel = new IdentifierEditorViewModel("DOI", new WordSuggestionProvider("DOI"), new CurrentThreadTaskExecutor(), mock(DialogService.class)); + viewModel = new IdentifierEditorViewModel("DOI", new WordSuggestionProvider("DOI"), new CurrentThreadTaskExecutor(), mock(DialogService.class), mock(FieldCheckers.class)); } @Test