1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.colorchooser; 27 28 import java.awt.event.FocusEvent; 29 import java.awt.event.FocusListener; 30 import java.text.ParseException; 31 import static java.util.Locale.ENGLISH; 32 import javax.swing.JFormattedTextField; 33 import javax.swing.JFormattedTextField.AbstractFormatter; 34 import javax.swing.SwingConstants; 35 import javax.swing.SwingUtilities; 36 import javax.swing.text.AttributeSet; 37 import javax.swing.text.BadLocationException; 38 import javax.swing.text.DefaultFormatterFactory; 39 import javax.swing.text.DocumentFilter; 40 41 @SuppressWarnings("serial") // Same-version serialization only 42 final class ValueFormatter extends AbstractFormatter implements FocusListener, Runnable { 43 44 static void init(int length, boolean hex, JFormattedTextField text) { 45 ValueFormatter formatter = new ValueFormatter(length, hex); 46 text.setColumns(length); 47 text.setFormatterFactory(new DefaultFormatterFactory(formatter)); 48 text.setHorizontalAlignment(SwingConstants.RIGHT); 49 text.setMinimumSize(text.getPreferredSize()); 50 text.addFocusListener(formatter); 51 } 52 53 private final DocumentFilter filter = new DocumentFilter() { 54 @Override 55 public void remove(FilterBypass fb, int offset, int length) throws BadLocationException { 56 if (isValid(fb.getDocument().getLength() - length)) { 57 fb.remove(offset, length); 58 } 59 } 60 61 @Override 62 public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet set) throws BadLocationException { 63 if (isValid(fb.getDocument().getLength() + text.length() - length) && isValid(text)) { 64 fb.replace(offset, length, text.toUpperCase(ENGLISH), set); 65 } 66 } 67 68 @Override 69 public void insertString(FilterBypass fb, int offset, String text, AttributeSet set) throws BadLocationException { 70 if (isValid(fb.getDocument().getLength() + text.length()) && isValid(text)) { 71 fb.insertString(offset, text.toUpperCase(ENGLISH), set); 72 } 73 } 74 }; 75 76 private final int length; 77 private final int radix; 78 79 private JFormattedTextField text; 80 81 ValueFormatter(int length, boolean hex) { 82 this.length = length; 83 this.radix = hex ? 16 : 10; 84 } 85 86 @Override 87 public Object stringToValue(String text) throws ParseException { 88 try { 89 return Integer.valueOf(text, this.radix); 90 } 91 catch (NumberFormatException nfe) { 92 ParseException pe = new ParseException("illegal format", 0); 93 pe.initCause(nfe); 94 throw pe; 95 } 96 } 97 98 @Override 99 public String valueToString(Object object) throws ParseException { 100 if (object instanceof Integer) { 101 if (this.radix == 10) { 102 return object.toString(); 103 } 104 int value = (Integer) object; 105 int index = this.length; 106 char[] array = new char[index]; 107 while (0 < index--) { 108 array[index] = Character.forDigit(value & 0x0F, this.radix); 109 value >>= 4; 110 } 111 return new String(array).toUpperCase(ENGLISH); 112 } 113 throw new ParseException("illegal object", 0); 114 } 115 116 @Override 117 protected DocumentFilter getDocumentFilter() { 118 return this.filter; 119 } 120 121 public void focusGained(FocusEvent event) { 122 Object source = event.getSource(); 123 if (source instanceof JFormattedTextField) { 124 this.text = (JFormattedTextField) source; 125 SwingUtilities.invokeLater(this); 126 } 127 } 128 129 public void focusLost(FocusEvent event) { 130 } 131 132 public void run() { 133 if (this.text != null) { 134 this.text.selectAll(); 135 } 136 } 137 138 private boolean isValid(int length) { 139 return (0 <= length) && (length <= this.length); 140 } 141 142 private boolean isValid(String text) { 143 int length = text.length(); 144 for (int i = 0; i < length; i++) { 145 char ch = text.charAt(i); 146 if (Character.digit(ch, this.radix) < 0) { 147 return false; 148 } 149 } 150 return true; 151 } 152 }