diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogView.java b/src/main/java/org/jabref/gui/groups/GroupDialogView.java index 67b7122c553..9d11fc25bb4 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogView.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogView.java @@ -3,7 +3,9 @@ import java.util.EnumMap; import javafx.application.Platform; +import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; import javafx.scene.control.ColorPicker; @@ -59,8 +61,8 @@ public class GroupDialogView extends BaseDialog { @FXML private TextField texGroupFilePath; - private final EnumMap hierarchyText = new EnumMap<>(GroupHierarchyType.class); - private final EnumMap hierarchyToolTip = new EnumMap<>(GroupHierarchyType.class); + private final EnumMap hierarchyText = new EnumMap<>(GroupHierarchyType.class); + private final EnumMap hierarchyToolTip = new EnumMap<>(GroupHierarchyType.class); private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer(); private final GroupDialogViewModel viewModel; @@ -80,6 +82,10 @@ public GroupDialogView(DialogService dialogService, BibDatabaseContext currentDa setResultConverter(viewModel::resultConverter); getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); + + final Button confirmDialogButton = (Button) getDialogPane().lookupButton(ButtonType.OK); + // handle validation before closing dialog and calling resultConverter + confirmDialogButton.addEventFilter(ActionEvent.ACTION, viewModel::validationHandler); } @FXML @@ -135,11 +141,12 @@ public void initialize() { validationVisualizer.initVisualization(viewModel.searchSearchTermEmptyValidationStatus(), searchGroupSearchTerm); validationVisualizer.initVisualization(viewModel.keywordRegexValidationStatus(), keywordGroupSearchTerm); validationVisualizer.initVisualization(viewModel.keywordSearchTermEmptyValidationStatus(), keywordGroupSearchTerm); + validationVisualizer.initVisualization(viewModel.keywordFieldEmptyValidationStatus(), keywordGroupSearchField); }); // Binding to the button throws a NPE, since it doesn't exist yet. Working around. - viewModel.validationStatus().validProperty().addListener((obs, oldValue, newValue) -> { - if (newValue) { + viewModel.validationStatus().validProperty().addListener((obs, _oldValue, validationStatus) -> { + if (validationStatus) { getDialogPane().lookupButton(ButtonType.OK).setDisable(false); } else { getDialogPane().lookupButton(ButtonType.OK).setDisable(true); diff --git a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java index 2a465886d3d..2da487145e3 100644 --- a/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java +++ b/src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java @@ -18,6 +18,7 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; +import javafx.event.Event; import javafx.scene.control.ButtonType; import javafx.scene.paint.Color; @@ -56,7 +57,6 @@ import de.saxsys.mvvmfx.utils.validation.Validator; public class GroupDialogViewModel { - // Basic Settings private final StringProperty nameProperty = new SimpleStringProperty(""); private final StringProperty descriptionProperty = new SimpleStringProperty(""); @@ -95,6 +95,7 @@ public class GroupDialogViewModel { private Validator nameContainsDelimiterValidator; private Validator sameNameValidator; private Validator keywordRegexValidator; + private Validator keywordFieldEmptyValidator; private Validator keywordSearchTermEmptyValidator; private Validator searchRegexValidator; private Validator searchSearchTermEmptyValidator; @@ -173,6 +174,11 @@ private void setupValidation() { Localization.lang("Keywords"), Localization.lang("Invalid regular expression.")))); + keywordFieldEmptyValidator = new FunctionBasedValidator<>( + keywordGroupSearchFieldProperty, + StringUtil::isNotBlank, + ValidationMessage.error(Localization.lang("Please enter a field name to search for keywords."))); + keywordSearchTermEmptyValidator = new FunctionBasedValidator<>( keywordGroupSearchTermProperty, input -> !StringUtil.isNullOrEmpty(input), @@ -214,103 +220,106 @@ private void setupValidation() { validator.addValidators(nameValidator, sameNameValidator); - typeSearchProperty.addListener((obs,oldVal,newVal) -> { - if (newVal) { + typeSearchProperty.addListener((obs, _oldValue, isSelected) -> { + if (isSelected) { validator.addValidators(searchRegexValidator, searchSearchTermEmptyValidator); } else { validator.removeValidators(searchRegexValidator, searchSearchTermEmptyValidator); } }); - typeKeywordsProperty.addListener((obs,oldVal,newVal) -> { - if (newVal) { - validator.addValidators(keywordRegexValidator, keywordSearchTermEmptyValidator); + typeKeywordsProperty.addListener((obs, _oldValue, isSelected) -> { + if (isSelected) { + validator.addValidators(keywordFieldEmptyValidator, keywordRegexValidator, keywordSearchTermEmptyValidator); } else { - validator.removeValidators(keywordRegexValidator, keywordSearchTermEmptyValidator); + validator.removeValidators(keywordFieldEmptyValidator, keywordRegexValidator, keywordSearchTermEmptyValidator); } }); } + public void validationHandler(Event event) { + ValidationStatus validationStatus = validator.getValidationStatus(); + if (validationStatus.getHighestMessage().isPresent()) { + dialogService.showErrorDialogAndWait(validationStatus.getHighestMessage().get().getMessage()); + // consume the event to prevent the dialog to close + event.consume(); + } + } + public AbstractGroup resultConverter(ButtonType button) { - if (button == ButtonType.OK) { - ValidationStatus validationStatus = validator.getValidationStatus(); - if (validationStatus.getHighestMessage().isPresent()) { - dialogService.showErrorDialogAndWait(validationStatus.getHighestMessage().get().getMessage()); - return null; - } + if (button != ButtonType.OK) { + return null; + } - AbstractGroup resultingGroup = null; - try { - String groupName = nameProperty.getValue().trim(); - if (typeExplicitProperty.getValue()) { - resultingGroup = new ExplicitGroup( + AbstractGroup resultingGroup = null; + try { + String groupName = nameProperty.getValue().trim(); + if (typeExplicitProperty.getValue()) { + resultingGroup = new ExplicitGroup( + groupName, + groupHierarchySelectedProperty.getValue(), + preferencesService.getKeywordDelimiter()); + } else if (typeKeywordsProperty.getValue()) { + if (keywordGroupRegexProperty.getValue()) { + resultingGroup = new RegexKeywordGroup( groupName, groupHierarchySelectedProperty.getValue(), - preferencesService.getKeywordDelimiter()); - } else if (typeKeywordsProperty.getValue()) { - if (keywordGroupRegexProperty.getValue()) { - resultingGroup = new RegexKeywordGroup( - groupName, - groupHierarchySelectedProperty.getValue(), - FieldFactory.parseField(keywordGroupSearchFieldProperty.getValue().trim()), - keywordGroupSearchTermProperty.getValue().trim(), - keywordGroupCaseSensitiveProperty.getValue()); - } else { - resultingGroup = new WordKeywordGroup( - groupName, - groupHierarchySelectedProperty.getValue(), - FieldFactory.parseField(keywordGroupSearchFieldProperty.getValue().trim()), - keywordGroupSearchTermProperty.getValue().trim(), - keywordGroupCaseSensitiveProperty.getValue(), - preferencesService.getKeywordDelimiter(), - false); - } - } else if (typeSearchProperty.getValue()) { - resultingGroup = new SearchGroup( + FieldFactory.parseField(keywordGroupSearchFieldProperty.getValue().trim()), + keywordGroupSearchTermProperty.getValue().trim(), + keywordGroupCaseSensitiveProperty.getValue()); + } else { + resultingGroup = new WordKeywordGroup( groupName, groupHierarchySelectedProperty.getValue(), - searchGroupSearchTermProperty.getValue().trim(), - searchGroupCaseSensitiveProperty.getValue(), - searchGroupRegexProperty.getValue()); - } else if (typeAutoProperty.getValue()) { - if (autoGroupKeywordsOptionProperty.getValue()) { - resultingGroup = new AutomaticKeywordGroup( - groupName, - groupHierarchySelectedProperty.getValue(), - FieldFactory.parseField(autoGroupKeywordsFieldProperty.getValue().trim()), - autoGroupKeywordsDelimiterProperty.getValue().charAt(0), - autoGroupKeywordsHierarchicalDelimiterProperty.getValue().charAt(0)); - } else { - resultingGroup = new AutomaticPersonsGroup( - groupName, - groupHierarchySelectedProperty.getValue(), - FieldFactory.parseField(autoGroupPersonsFieldProperty.getValue().trim())); - } - } else if (typeTexProperty.getValue()) { - resultingGroup = TexGroup.create( + FieldFactory.parseField(keywordGroupSearchFieldProperty.getValue().trim()), + keywordGroupSearchTermProperty.getValue().trim(), + keywordGroupCaseSensitiveProperty.getValue(), + preferencesService.getKeywordDelimiter(), + false); + } + } else if (typeSearchProperty.getValue()) { + resultingGroup = new SearchGroup( + groupName, + groupHierarchySelectedProperty.getValue(), + searchGroupSearchTermProperty.getValue().trim(), + searchGroupCaseSensitiveProperty.getValue(), + searchGroupRegexProperty.getValue()); + } else if (typeAutoProperty.getValue()) { + if (autoGroupKeywordsOptionProperty.getValue()) { + resultingGroup = new AutomaticKeywordGroup( groupName, groupHierarchySelectedProperty.getValue(), - Paths.get(texGroupFilePathProperty.getValue().trim()), - new DefaultAuxParser(new BibDatabase()), - Globals.getFileUpdateMonitor(), - currentDatabase.getMetaData()); - } - - if (resultingGroup != null) { - resultingGroup.setColor(colorProperty.getValue()); - resultingGroup.setDescription(descriptionProperty.getValue()); - resultingGroup.setIconName(iconProperty.getValue()); - return resultingGroup; + FieldFactory.parseField(autoGroupKeywordsFieldProperty.getValue().trim()), + autoGroupKeywordsDelimiterProperty.getValue().charAt(0), + autoGroupKeywordsHierarchicalDelimiterProperty.getValue().charAt(0)); } else { - return null; + resultingGroup = new AutomaticPersonsGroup( + groupName, + groupHierarchySelectedProperty.getValue(), + FieldFactory.parseField(autoGroupPersonsFieldProperty.getValue().trim())); } + } else if (typeTexProperty.getValue()) { + resultingGroup = TexGroup.create( + groupName, + groupHierarchySelectedProperty.getValue(), + Paths.get(texGroupFilePathProperty.getValue().trim()), + new DefaultAuxParser(new BibDatabase()), + Globals.getFileUpdateMonitor(), + currentDatabase.getMetaData()); + } - } catch (IllegalArgumentException | IOException exception) { - dialogService.showErrorDialogAndWait(exception.getLocalizedMessage(), exception); - return null; + if (resultingGroup != null) { + resultingGroup.setColor(colorProperty.getValue()); + resultingGroup.setDescription(descriptionProperty.getValue()); + resultingGroup.setIconName(iconProperty.getValue()); + return resultingGroup; } + + return null; + } catch (IllegalArgumentException | IOException exception) { + dialogService.showErrorDialogAndWait(exception.getLocalizedMessage(), exception); + return null; } - return null; } public void setValues() { @@ -397,69 +406,139 @@ private List getFileDirectoriesAsPaths() { return fileDirs; } - public ValidationStatus validationStatus() { return validator.getValidationStatus(); } + public ValidationStatus validationStatus() { + return validator.getValidationStatus(); + } - public ValidationStatus nameValidationStatus() { return nameValidator.getValidationStatus(); } + public ValidationStatus nameValidationStatus() { + return nameValidator.getValidationStatus(); + } - public ValidationStatus nameContainsDelimiterValidationStatus() { return nameContainsDelimiterValidator.getValidationStatus(); } + public ValidationStatus nameContainsDelimiterValidationStatus() { + return nameContainsDelimiterValidator.getValidationStatus(); + } - public ValidationStatus sameNameValidationStatus() { return sameNameValidator.getValidationStatus(); } + public ValidationStatus sameNameValidationStatus() { + return sameNameValidator.getValidationStatus(); + } - public ValidationStatus searchRegexValidationStatus() { return searchRegexValidator.getValidationStatus(); } + public ValidationStatus searchRegexValidationStatus() { + return searchRegexValidator.getValidationStatus(); + } - public ValidationStatus searchSearchTermEmptyValidationStatus() { return searchSearchTermEmptyValidator.getValidationStatus(); } + public ValidationStatus searchSearchTermEmptyValidationStatus() { + return searchSearchTermEmptyValidator.getValidationStatus(); + } - public ValidationStatus keywordRegexValidationStatus() { return keywordRegexValidator.getValidationStatus(); } + public ValidationStatus keywordRegexValidationStatus() { + return keywordRegexValidator.getValidationStatus(); + } - public ValidationStatus keywordSearchTermEmptyValidationStatus() { return keywordSearchTermEmptyValidator.getValidationStatus(); } + public ValidationStatus keywordFieldEmptyValidationStatus() { + return keywordFieldEmptyValidator.getValidationStatus(); + } - public StringProperty nameProperty() { return nameProperty; } + public ValidationStatus keywordSearchTermEmptyValidationStatus() { + return keywordSearchTermEmptyValidator.getValidationStatus(); + } - public StringProperty descriptionProperty() { return descriptionProperty; } + public StringProperty nameProperty() { + return nameProperty; + } - public StringProperty iconProperty() { return iconProperty; } + public StringProperty descriptionProperty() { + return descriptionProperty; + } - public ObjectProperty colorFieldProperty() { return colorProperty; } + public StringProperty iconProperty() { + return iconProperty; + } - public ListProperty groupHierarchyListProperty() { return groupHierarchyListProperty; } + public ObjectProperty colorFieldProperty() { + return colorProperty; + } - public ObjectProperty groupHierarchySelectedProperty() { return groupHierarchySelectedProperty; } + public ListProperty groupHierarchyListProperty() { + return groupHierarchyListProperty; + } - public BooleanProperty typeExplicitProperty() { return typeExplicitProperty; } + public ObjectProperty groupHierarchySelectedProperty() { + return groupHierarchySelectedProperty; + } - public BooleanProperty typeKeywordsProperty() { return typeKeywordsProperty; } + public BooleanProperty typeExplicitProperty() { + return typeExplicitProperty; + } - public BooleanProperty typeSearchProperty() { return typeSearchProperty; } + public BooleanProperty typeKeywordsProperty() { + return typeKeywordsProperty; + } + + public BooleanProperty typeSearchProperty() { + return typeSearchProperty; + } - public BooleanProperty typeAutoProperty() { return typeAutoProperty; } + public BooleanProperty typeAutoProperty() { + return typeAutoProperty; + } - public BooleanProperty typeTexProperty() { return typeTexProperty; } + public BooleanProperty typeTexProperty() { + return typeTexProperty; + } - public StringProperty keywordGroupSearchTermProperty() { return keywordGroupSearchTermProperty; } + public StringProperty keywordGroupSearchTermProperty() { + return keywordGroupSearchTermProperty; + } - public StringProperty keywordGroupSearchFieldProperty() { return keywordGroupSearchFieldProperty; } + public StringProperty keywordGroupSearchFieldProperty() { + return keywordGroupSearchFieldProperty; + } - public BooleanProperty keywordGroupCaseSensitiveProperty() { return keywordGroupCaseSensitiveProperty; } + public BooleanProperty keywordGroupCaseSensitiveProperty() { + return keywordGroupCaseSensitiveProperty; + } - public BooleanProperty keywordGroupRegexProperty() { return keywordGroupRegexProperty; } + public BooleanProperty keywordGroupRegexProperty() { + return keywordGroupRegexProperty; + } - public StringProperty searchGroupSearchTermProperty() { return searchGroupSearchTermProperty; } + public StringProperty searchGroupSearchTermProperty() { + return searchGroupSearchTermProperty; + } - public BooleanProperty searchGroupCaseSensitiveProperty() { return searchGroupCaseSensitiveProperty; } + public BooleanProperty searchGroupCaseSensitiveProperty() { + return searchGroupCaseSensitiveProperty; + } - public BooleanProperty searchGroupRegexProperty() { return searchGroupRegexProperty; } + public BooleanProperty searchGroupRegexProperty() { + return searchGroupRegexProperty; + } - public BooleanProperty autoGroupKeywordsOptionProperty() { return autoGroupKeywordsOptionProperty; } + public BooleanProperty autoGroupKeywordsOptionProperty() { + return autoGroupKeywordsOptionProperty; + } - public StringProperty autoGroupKeywordsFieldProperty() { return autoGroupKeywordsFieldProperty; } + public StringProperty autoGroupKeywordsFieldProperty() { + return autoGroupKeywordsFieldProperty; + } - public StringProperty autoGroupKeywordsDeliminatorProperty() { return autoGroupKeywordsDelimiterProperty; } + public StringProperty autoGroupKeywordsDeliminatorProperty() { + return autoGroupKeywordsDelimiterProperty; + } - public StringProperty autoGroupKeywordsHierarchicalDeliminatorProperty() { return autoGroupKeywordsHierarchicalDelimiterProperty; } + public StringProperty autoGroupKeywordsHierarchicalDeliminatorProperty() { + return autoGroupKeywordsHierarchicalDelimiterProperty; + } - public BooleanProperty autoGroupPersonsOptionProperty() { return autoGroupPersonsOptionProperty; } + public BooleanProperty autoGroupPersonsOptionProperty() { + return autoGroupPersonsOptionProperty; + } - public StringProperty autoGroupPersonsFieldProperty() { return autoGroupPersonsFieldProperty; } + public StringProperty autoGroupPersonsFieldProperty() { + return autoGroupPersonsFieldProperty; + } - public StringProperty texGroupFilePathProperty() { return texGroupFilePathProperty; } + public StringProperty texGroupFilePathProperty() { + return texGroupFilePathProperty; + } } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0af1b17e915..306d6291454 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2107,6 +2107,7 @@ Unable\ to\ open\ ShortScience.=Unable to open ShortScience. Shared\ database=Shared database Lookup=Lookup +Please\ enter\ a\ field\ name\ to\ search\ for\ keywords.=Please enter a field name to search for keywords. Access\ date\ of\ the\ address\ specified\ in\ the\ url\ field.=Access date of the address specified in the url field. Additional\ information\ related\ to\ the\ resource\ indicated\ by\ the\ eprint\ field.=Additional information related to the resource indicated by the eprint field. Annex\ to\ the\ eventtitle\ field.=Annex to the eventtitle field.