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

jdplus.toolkit.desktop.plugin.util.JTextComponents Maven / Gradle / Ivy

/*
 * Copyright 2016 National Bank of Belgium
 * 
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved 
 * by the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * 
 * http://ec.europa.eu/idabc/eupl
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and 
 * limitations under the Licence.
 */
package jdplus.toolkit.desktop.plugin.util;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;
import javax.swing.text.NumberFormatter;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.text.*;
import java.util.Optional;
import java.util.function.IntSupplier;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 *
 * @author Philippe Charles
 * @since 2.2.0
 */
public final class JTextComponents {

    private JTextComponents() {
        // static class
    }

    public static void enableDecimalMappingOnNumpad(JFormattedTextField component) {
        enableDecimalMappingOnNumpad(component, () -> {
            JFormattedTextField.AbstractFormatter af = component.getFormatter();
            if (af instanceof NumberFormatter) {
                Format format = ((NumberFormatter) af).getFormat();
                if (format instanceof DecimalFormat) {
                    return ((DecimalFormat) format).getDecimalFormatSymbols().getDecimalSeparator();
                }
            }
            return '.';
        });
    }

    public static void enableDecimalMappingOnNumpad(JTextComponent component, IntSupplier decimalSeparator) {
        component.addKeyListener(new KeyAdapter() {
            private boolean mappingRequested = false;

            private boolean isDecimalKeyOnNumpad(KeyEvent e) {
                return e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD
                        && e.getKeyCode() == KeyEvent.VK_DECIMAL;
            }

            private boolean isDecimalSeparator(KeyEvent e) {
                return e.getKeyChar() == decimalSeparator.getAsInt();
            }

            @Override
            public void keyTyped(KeyEvent e) {
                if (mappingRequested) {
                    e.setKeyChar((char) decimalSeparator.getAsInt());
                    mappingRequested = false;
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                mappingRequested = false;
            }

            @Override
            public void keyPressed(KeyEvent e) {
                mappingRequested = isDecimalKeyOnNumpad(e) && !isDecimalSeparator(e);
            }
        });
    }

    public static void enableValidationFeedback(JTextComponent component, Predicate validator) {
        enableValidationFeedback(component, validator, JTextComponents::getInvalidForeground);
    }

    public static void enableValidationFeedback(JTextComponent component, Predicate validator, Supplier feedbackColor) {
        component.getDocument().addDocumentListener(new DocumentListener() {
            private final Color valid = component.getForeground();

            @Override
            public void insertUpdate(DocumentEvent e) {
                updateForeground();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateForeground();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
            }

            private void updateForeground() {
                component.setForeground(validator.test(component.getText()) ? valid : feedbackColor.get());
            }
        });
    }

    public static boolean isDouble(NumberFormat format, String input) {
        ParsePosition pos = new ParsePosition(0);
        return format.parse(input, pos) != null
                && !(pos.getIndex() != input.length() || pos.getErrorIndex() != -1);
    }

    public static void fixMaxDecimals(NumberFormat format) {
        format.setMinimumFractionDigits(0);
        format.setMaximumFractionDigits(64);
    }

    public static Optional peekValue(JFormattedTextField component) {
        try {
            return Optional.ofNullable(component.getFormatter().stringToValue(component.getText()));
        } catch (ParseException ex) {
            return Optional.empty();
        }
    }

    public static Color getInvalidForeground() {
        return Color.RED;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy