Skip to content

Commit

Permalink
Add validation to entry editor (#3090)
Browse files Browse the repository at this point in the history
* Add validation to entry editor

* Fix build
  • Loading branch information
tobiasdiez authored Aug 10, 2017
1 parent 451d829 commit f0b90ba
Show file tree
Hide file tree
Showing 51 changed files with 259 additions and 81 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -26,6 +27,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- We fixed an issue where <kbd>DEL</kbd>, <kbd>Ctrl</kbd>+<kbd>C</kbd>, <kbd>Ctrl</kbd>+<kbd>V</kbd> and <kbd>Ctrl</kbd>+<kbd>A</kbd> 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


Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
5 changes: 5 additions & 0 deletions external-libraries.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,38 @@
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 {
protected final String fieldName;
protected StringProperty text = new SimpleStringProperty("");
protected BibEntry entry;
private final AutoCompleteSuggestionProvider<?> suggestionProvider;
private final CompositeValidator fieldValidator;
private ObjectBinding<String> 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<String> validator = new FunctionBasedValidator<>(text, value ->
checker.checkValue(value).map(ValidationMessage::warning).orElse(null));
fieldValidator.addValidators(validator);
}
}

public Validator getFieldValidator() {
return fieldValidator;
}

public StringProperty textProperty() {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/jabref/gui/fieldeditors/DateEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
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 {

@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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -10,8 +11,8 @@ public class EditorTypeEditorViewModel extends MapBasedEditorViewModel<String> {

private BiMap<String, String> 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"));
Expand Down
37 changes: 20 additions & 17 deletions src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -10,8 +11,8 @@ public class GenderEditorViewModel extends MapBasedEditorViewModel<String> {

private BiMap<String, String> 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"));
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/jabref/gui/fieldeditors/IdentifierEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,8 +32,8 @@ public class IdentifierEditor extends HBox implements FieldEditorFX {
@FXML private Button lookupIdentifierButton;
private Optional<BibEntry> 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);

Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
10 changes: 8 additions & 2 deletions src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,31 @@
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<BibEntry> 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);

textArea.textProperty().bindBidirectional(viewModel.textProperty());
textArea.addToContextMenu(EditorMenus.getDefaultMenu(textArea));

AutoCompletionTextInputBinding.autoComplete(textArea, viewModel::complete);

ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer();
validationVisualizer.initVisualization(viewModel.getFieldValidator().getValidationStatus(), textArea);
}

public JournalEditorViewModel getViewModel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Loading

0 comments on commit f0b90ba

Please sign in to comment.