All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.jonestimd.swing.component.TextField Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
// Copyright (c) 2016 Timothy D. Jones
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package io.github.jonestimd.swing.component;

import java.text.Format;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.function.Predicate;
import java.util.regex.Pattern;

import javax.swing.JFormattedTextField;
import javax.swing.JTextField;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

import io.github.jonestimd.swing.validation.NumberValidator;
import io.github.jonestimd.swing.validation.PositiveNumberValidator;
import io.github.jonestimd.swing.validation.RequiredValidator;
import io.github.jonestimd.swing.validation.ValidatedTextField;
import io.github.jonestimd.swing.validation.Validator;

/**
 * Builder for initializing a {@link JTextField}.
 * @param  the class of the text field
 */
public class TextField {
    private final T textField;

    public TextField(T textField) {
        this.textField = textField;
    }

    /**
     * Set the text field to read only.
     * @return this {@code TextField} for further configuration
     */
    public TextField readOnly() {
        textField.setEditable(false);
        return this;
    }

    /**
     * Set the text field to be right aligned.
     * @return this {@code TextField} for further configuration
     */
    public TextField rightAligned() {
        textField.setHorizontalAlignment(JTextField.RIGHT);
        return this;
    }

    /**
     * Set the {@link DocumentFilter} to filter input using a regex pattern.
     * @param pattern the regex pattern to use for filtering input
     * @return this {@code TextField} for further configuration
     */
    public TextField inputFilter(String pattern) {
        Pattern regex = Pattern.compile(pattern);
        return inputFilter((s) -> regex.matcher(s).matches());
    }

    /**
     * Set the {@link DocumentFilter} to filter input using a predicate.
     * @param filter the predicate to use for filtering input
     * @return this {@code TextField} for further configuration
     */
    public TextField inputFilter(Predicate filter) {
        ((AbstractDocument) textField.getDocument()).setDocumentFilter(new DocumentFilter() {
            @Override
            public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {
                if (filter.test(text)) super.insertString(fb, offset, text, attr);
            }

            @Override
            public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
                if (filter.test(text)) super.replace(fb, offset, length, text, attrs);
            }
        });
        return this;
    }

    /**
     * @return the configured text field
     */
    public T get() {
        return textField;
    }

    /**
     * Create a {@link JFormattedTextField} using the specified format.
     * @return a {@code TextField} for further configuration
     */
    public static TextField formatted(Format format) {
        return new TextField<>(new JFormattedTextField(format));
    }

    /**
     * Create a {@link JTextField} with the default configuration.
     * @return a {@code TextField} for further configuration
     */
    public static TextField plain() {
        return new TextField<>(new JTextField());
    }

    /**
     * Create a factory for initializing a validated text field.
     * @param bundle the resource bundle for validation messages
     * @param resourcePrefix the resource key prefix for validation messages
     * @return an instance of {@link Validated} for further configuration.
     */
    public static Validated validated(ResourceBundle bundle, String resourcePrefix) {
        return new Validated(bundle, resourcePrefix);
    }

    /**
     * Factory class for creating a {@link ValidatedTextField}.
     */
    public static class Validated {
        private final ResourceBundle bundle;
        private final String resourcePrefix;
        private final List> validators = new ArrayList<>();

        private Validated(ResourceBundle bundle, String resourcePrefix) {
            this.bundle = bundle;
            this.resourcePrefix = resourcePrefix;
        }

        /**
         * Add a {@link RequiredValidator}.
         * @param message the resource key suffix for the validation error message
         * @return this {@code Validated} factory for further configuration
         */
        public Validated required(String message) {
            validators.add(new RequiredValidator(bundle.getString(resourcePrefix + message)));
            return this;
        }

        /**
         * Add a {@link NumberValidator}.
         * @param message the resource key suffix for the validation error message
         * @return this {@code Validated} factory for further configuration
         */
        public Validated numeric(String message) {
            validators.add(new NumberValidator(bundle.getString(resourcePrefix + message)));
            return this;
        }

        /**
         * Add a {@link PositiveNumberValidator}.
         * @param message the resource key suffix for the validation error message
         * @return this {@code Validated} factory for further configuration
         */
        public Validated positiveNumber(String message) {
            validators.add(new PositiveNumberValidator(bundle.getString(resourcePrefix + message)));
            return this;
        }

        /**
         * Add the specified validator to the text field.
         * @return this {@code Validated} factory for further configuration
         */
        public Validated add(Validator validator) {
            validators.add(validator);
            return this;
        }

        /**
         * Create and configure the {@link ValidatedTextField}.
         */
        public ValidatedTextField get() {
            Validator validator = validators.stream().reduce(Validator::then).orElseThrow(IllegalStateException::new);
            return new ValidatedTextField(validator);
        }

        /**
         * Create and initialize the {@link ValidatedTextField}.
         * @return an instance of {@link TextField} for further configuration
         */
        public TextField configure() {
            return new TextField<>(get());
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy