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

org.nuiton.jaxx.widgets.jformattedtextfield.JFormattedTextFieldNavigationManager Maven / Gradle / Ivy

package org.nuiton.jaxx.widgets.jformattedtextfield;

/*
 * #%L
 * JAXX :: Widgets
 * %%
 * Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.common.base.Preconditions;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.swing.JFormattedTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.MaskFormatter;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;

/**
 * Manager to navigate inside a JFormattedTextField using a MaskFormatter.
 * 

* Created on 3/21/15. * * @author Tony Chemit - [email protected] * @since 2.23 */ public class JFormattedTextFieldNavigationManager { /** * Logger. */ private static final Logger log = LogManager.getLogger(JFormattedTextFieldNavigationManager.class); private static final String CLIENT_PROPERTY_NAVIGATION_MANAGER = "JFormattedTextFieldNavigationHandler"; private final JFormatterTextFieldInternalGroups groups; private final KeyAdapter keyAdapter; private final MouseAdapter mouseAdapter; private final FocusAdapter focusAdapter; private final Map actions; private JFormatterTextFieldInternalGroup lastGroup = null; private static class SelectComponentAction implements Runnable { private final JFormatterTextFieldInternalGroup group; private final JFormattedTextField source; private SelectComponentAction(JFormattedTextField source, JFormatterTextFieldInternalGroup group) { this.group = group; this.source = source; } @Override public void run() { int startIndex = group.getStartIndex(); int endIndex = group.getEndIndex() + 1; if (log.isDebugEnabled()) { log.debug(String.format("Select group [%s]", group)); } source.select(startIndex, endIndex); } } public static void install(JFormattedTextField component) { JFormattedTextField.AbstractFormatter formatter = component.getFormatter(); Preconditions.checkState(formatter != null, "No formatter found on " + component); Preconditions.checkState(formatter instanceof MaskFormatter, "Formatter " + formatter + " is not a MaskFormatter"); String mask = ((MaskFormatter) formatter).getMask(); JFormatterTextFieldInternalGroups componentPositions = JFormatterTextFieldInternalGroups.create(mask); JFormattedTextFieldNavigationManager handler = new JFormattedTextFieldNavigationManager(componentPositions, component); component.putClientProperty(CLIENT_PROPERTY_NAVIGATION_MANAGER, handler); handler.install0(component); } public static void uninstall(JFormattedTextField component) { JFormattedTextFieldNavigationManager handler = (JFormattedTextFieldNavigationManager) component.getClientProperty(CLIENT_PROPERTY_NAVIGATION_MANAGER); try { handler.uninstall0(component); } finally { component.putClientProperty(CLIENT_PROPERTY_NAVIGATION_MANAGER, null); } } protected JFormattedTextFieldNavigationManager(JFormatterTextFieldInternalGroups groups, JFormattedTextField component) { this.groups = groups; this.actions = new HashMap<>(); for (JFormatterTextFieldInternalGroup componentPosition : groups) { actions.put(componentPosition, new SelectComponentAction(component, componentPosition)); } this.keyAdapter = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { JFormattedTextField source = (JFormattedTextField) e.getSource(); int caretPosition = source.getCaretPosition(); if (canGoRight(e)) { goRight(source, caretPosition); e.consume(); } else if (canTransferFocus(e)) { source.transferFocus(); e.consume(); } else if (canGoLeft(e)) { goLeft(source, caretPosition); e.consume(); } else if (canTransferFocusBackward(e)) { source.transferFocusBackward(); e.consume(); } } @Override public void keyReleased(KeyEvent e) { JFormattedTextField source = (JFormattedTextField) e.getSource(); JFormatterTextFieldInternalGroup currentGroup = getCurrentGroup(source); selectComponent(currentGroup); } }; this.mouseAdapter = new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { JFormattedTextField source = (JFormattedTextField) e.getSource(); JFormatterTextFieldInternalGroup currentGroup = getCurrentGroup(source); selectComponent(currentGroup); } }; this.focusAdapter = new FocusAdapter() { @Override public void focusGained(FocusEvent e) { lastGroup = null; JFormattedTextField source = (JFormattedTextField) e.getSource(); JFormatterTextFieldInternalGroup currentGroup = getCurrentGroup(source); selectComponent(currentGroup); } }; } protected void gotoComponent(JFormattedTextField source, JFormatterTextFieldInternalGroup group) { if (group != null) { int startIndex = group.getStartIndex(); int endIndex = group.getEndIndex(); if (log.isDebugEnabled()) { log.debug(String.format("Goto component [%s - %s]", startIndex, endIndex)); } source.setCaretPosition(startIndex); } } protected void selectComponent(JFormatterTextFieldInternalGroup currentGroup) { if (lastGroup == null || !lastGroup.equals(currentGroup)) { if (log.isDebugEnabled()) { log.debug("New select group: " + currentGroup); } lastGroup = currentGroup; SelectComponentAction action = actions.get(currentGroup); if (action != null) { SwingUtilities.invokeLater(action); } } } protected JFormatterTextFieldInternalGroup getCurrentGroup(JFormattedTextField source) { return getGroup(source, source.getCaretPosition()); } protected JFormatterTextFieldInternalGroup getGroup(JFormattedTextField source, int caretPosition) { JFormatterTextFieldInternalGroup result = groups.getGroupAtPosition(caretPosition); if (result == null && caretPosition >= source.getText().length()) { result = groups.getGroupAtPosition(source.getText().length() - 1); } if (result == null) { result = groups.iterator().next(); } return result; } protected void goRight(JFormattedTextField source, int caretPosition) { if (lastGroup == null || !lastGroup.isLastGroup()) { if (log.isDebugEnabled()) { log.debug("Go right from position " + caretPosition); } JFormatterTextFieldInternalGroup currentGroup = getGroup(source, caretPosition); JFormatterTextFieldInternalGroup nextGroup = currentGroup.getNextGroup(); gotoComponent(source, nextGroup); } } protected void goLeft(JFormattedTextField source, int caretPosition) { if (lastGroup == null || !lastGroup.isFirstGroup()) { if (log.isDebugEnabled()) { log.debug("Go left from position " + caretPosition); } JFormatterTextFieldInternalGroup currentGroup = getGroup(source, caretPosition); JFormatterTextFieldInternalGroup nextGroup = currentGroup.getPreviousGroup(); gotoComponent(source, nextGroup); } } protected boolean canGoRight(KeyEvent e) { boolean result = false; boolean noModifiers = e.getModifiersEx() == 0; if (KeyEvent.VK_RIGHT == e.getKeyCode() && noModifiers) { // right key go to next component result = true; } else if (KeyEvent.VK_TAB == e.getKeyCode() && noModifiers) { // Tab go to next component if not on last one result = lastGroup == null || !lastGroup.isLastGroup(); } return result; } protected boolean canGoLeft(KeyEvent e) { boolean result = false; if (KeyEvent.VK_LEFT == e.getKeyCode() && e.getModifiersEx() == 0) { // Left key go to previous component result = true; } else if (KeyEvent.VK_TAB == e.getKeyCode() && e.isShiftDown() && !e.isControlDown()) { // Shift Tab go to previous component if not on first one result = lastGroup != null && !lastGroup.isFirstGroup(); } return result; } protected boolean canTransferFocus(KeyEvent e) { boolean result = false; boolean onTabKey = KeyEvent.VK_TAB == e.getKeyCode(); if (onTabKey && e.isControlDown() && !e.isShiftDown()) { // Ctrl Tab go direct to focus result = true; } else if (onTabKey && e.getModifiersEx() == 0) { // Tab on last component go to focus result = lastGroup != null && lastGroup.isLastGroup(); } return result; } protected boolean canTransferFocusBackward(KeyEvent e) { boolean result = false; boolean onShiftTabKey = KeyEvent.VK_TAB == e.getKeyCode() && e.isShiftDown(); if (onShiftTabKey && e.isControlDown()) { // Ctrl Shift Tab go direct to focus backward result = true; } else if (onShiftTabKey) { // Shit Tab go to focus backward only if no component selected or on the first one result = lastGroup == null || lastGroup.isFirstGroup(); } return result; } private void install0(JFormattedTextField component) { component.setFocusTraversalKeysEnabled(false); component.addKeyListener(keyAdapter); component.addMouseListener(mouseAdapter); component.addFocusListener(focusAdapter); } private void uninstall0(JFormattedTextField component) { component.setFocusTraversalKeysEnabled(true); component.removeKeyListener(keyAdapter); component.removeMouseListener(mouseAdapter); component.removeFocusListener(focusAdapter); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy