Show error below textinput instead of popup

This commit is contained in:
Christoph Atteneder 2018-10-22 11:57:32 +02:00
parent 6f1e74c780
commit f9478a5afc
No known key found for this signature in database
GPG Key ID: CD5DC1C529CDFD3B
5 changed files with 39 additions and 112 deletions

View File

@ -17,26 +17,13 @@
package bisq.desktop.components;
import bisq.core.locale.Res;
import bisq.desktop.util.validation.JFXInputValidator;
import bisq.core.util.validation.InputValidator;
import com.jfoenix.controls.JFXTextField;
import org.controlsfx.control.PopOver;
import javafx.stage.Window;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
@ -55,13 +42,10 @@ import javafx.beans.property.SimpleObjectProperty;
// consider replacement with controlsFX components.
public class InputTextField extends JFXTextField {
//private final Effect invalidEffect = new DropShadow(BlurType.THREE_PASS_BOX, Color.RED, 4, 0.0, 0, 0);
private final ObjectProperty<InputValidator.ValidationResult> validationResult = new SimpleObjectProperty<>
(new InputValidator.ValidationResult(true));
private static PopOver errorMessageDisplay;
private Region layoutReference = this;
private final JFXInputValidator jfxValidationWrapper = new JFXInputValidator();
public InputValidator getValidator() {
return validator;
@ -73,17 +57,6 @@ public class InputTextField extends JFXTextField {
private InputValidator validator;
///////////////////////////////////////////////////////////////////////////////////////////
// Static
///////////////////////////////////////////////////////////////////////////////////////////
public static void hideErrorMessageDisplay() {
if (errorMessageDisplay != null)
errorMessageDisplay.hide();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@ -91,21 +64,17 @@ public class InputTextField extends JFXTextField {
public InputTextField() {
super();
getValidators().add(jfxValidationWrapper);
validationResult.addListener((ov, oldValue, newValue) -> {
if (newValue != null) {
//setEffect(newValue.isValid ? null : invalidEffect);
if (newValue.isValid)
hideErrorMessageDisplay();
else
applyErrorMessage(newValue);
if (newValue.isValid) {
resetValidation();
} else {
jfxValidationWrapper.applyErrorMessage(newValue);
}
validate();
}
});
sceneProperty().addListener((ov, oldValue, newValue) -> {
// we got removed from the scene so hide the popup (if open)
if (newValue == null)
hideErrorMessageDisplay();
});
focusedProperty().addListener((o, oldValue, newValue) -> {
@ -120,24 +89,9 @@ public class InputTextField extends JFXTextField {
///////////////////////////////////////////////////////////////////////////////////////////
public void resetValidation() {
setEffect(null);
hideErrorMessageDisplay();
jfxValidationWrapper.resetValidation();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////////////////
/**
* @param layoutReference The node used as reference for positioning. If not set explicitly the
* ValidatingTextField instance is used.
*/
public void setLayoutReference(Region layoutReference) {
this.layoutReference = layoutReference;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////
@ -145,49 +99,4 @@ public class InputTextField extends JFXTextField {
public ObjectProperty<InputValidator.ValidationResult> validationResultProperty() {
return validationResult;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////////////////
private void applyErrorMessage(InputValidator.ValidationResult validationResult) {
if (errorMessageDisplay != null)
errorMessageDisplay.hide();
if (!validationResult.isValid) {
createErrorPopOver(validationResult.errorMessage);
if (getScene() != null)
errorMessageDisplay.show(getScene().getWindow(), getErrorPopupPosition().getX(),
getErrorPopupPosition().getY());
if (errorMessageDisplay != null)
errorMessageDisplay.setDetached(false);
}
}
private Point2D getErrorPopupPosition() {
Window window = getScene().getWindow();
Point2D point;
point = layoutReference.localToScene(0, 0);
double x = Math.floor(point.getX() + window.getX() + layoutReference.getWidth() + 20 - getPadding().getLeft() -
getPadding().getRight());
double y = Math.floor(point.getY() + window.getY() + getHeight() / 2 - getPadding().getTop() - getPadding()
.getBottom());
return new Point2D(x, y);
}
private static void createErrorPopOver(String errorMessage) {
Label errorLabel = new AutoTooltipLabel(errorMessage);
errorLabel.setId("validation-error");
errorLabel.setPadding(new Insets(0, 10, 0, 10));
errorLabel.setOnMouseClicked(e -> hideErrorMessageDisplay());
errorMessageDisplay = new PopOver(errorLabel);
errorMessageDisplay.setDetachable(true);
errorMessageDisplay.setDetachedTitle(Res.get("shared.close"));
errorMessageDisplay.setArrowIndent(5);
}
}

View File

@ -23,7 +23,6 @@ import bisq.desktop.components.AddressTextField;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.BalanceTextField;
import bisq.desktop.components.BusyAnimation;
import bisq.desktop.components.FundsTextField;
import bisq.desktop.components.InfoInputTextField;
import bisq.desktop.components.InputTextField;
@ -92,7 +91,6 @@ import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.geometry.HPos;
@ -837,7 +835,6 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
scrollPane.setFitToWidth(true);
scrollPane.setFitToHeight(true);
scrollPane.setOnScroll(e -> InputTextField.hideErrorMessageDisplay());
AnchorPane.setLeftAnchor(scrollPane, 0d);
AnchorPane.setTopAnchor(scrollPane, 0d);
AnchorPane.setRightAnchor(scrollPane, 0d);

View File

@ -21,7 +21,6 @@ import bisq.desktop.Navigation;
import bisq.desktop.common.view.ActivatableView;
import bisq.desktop.common.view.View;
import bisq.desktop.common.view.ViewLoader;
import bisq.desktop.components.InputTextField;
import bisq.desktop.main.MainView;
import bisq.desktop.main.offer.createoffer.CreateOfferView;
import bisq.desktop.main.offer.offerbook.OfferBookView;
@ -38,8 +37,6 @@ import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
import bisq.core.user.Preferences;
import bisq.common.UserThread;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.AnchorPane;
@ -88,7 +85,6 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> {
loadView(viewPath.tip());
};
tabChangeListener = (observableValue, oldValue, newValue) -> {
UserThread.execute(InputTextField::hideErrorMessageDisplay);
if (newValue != null) {
if (newValue.equals(createOfferTab) && createOfferView != null) {
createOfferView.onTabSelected(true);

View File

@ -674,7 +674,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
scrollPane.setFitToWidth(true);
scrollPane.setFitToHeight(true);
scrollPane.setOnScroll(e -> InputTextField.hideErrorMessageDisplay());
AnchorPane.setLeftAnchor(scrollPane, 0d);
AnchorPane.setTopAnchor(scrollPane, 0d);
AnchorPane.setRightAnchor(scrollPane, 0d);

View File

@ -0,0 +1,26 @@
package bisq.desktop.util.validation;
import bisq.core.util.validation.InputValidator;
import com.jfoenix.validation.base.ValidatorBase;
public class JFXInputValidator extends ValidatorBase {
public JFXInputValidator() {
super();
}
@Override
protected void eval() {
//Do nothing as validation is handled by current validation logic
}
public void resetValidation() {
hasErrors.set(false);
}
public void applyErrorMessage(InputValidator.ValidationResult newValue) {
message.set(newValue.errorMessage);
hasErrors.set(true);
}
}