Overwritable TextField
/* Core SWING Advanced Programming By Kim Topley ISBN: 0 13 083292 8 Publisher: Prentice Hall */ import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.UIManager; import javax.swing.plaf.TextUI; import javax.swing.text.BadLocationException; import javax.swing.text.Caret; import javax.swing.text.DefaultCaret; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Keymap; import javax.swing.text.TextAction; public class OverwritableTextField extends JTextField { public OverwritableTextField() { this(null, null, 0); } public OverwritableTextField(String text) { this(null, text, 0); } public OverwritableTextField(int columns) { this(null, null, columns); } public OverwritableTextField(String text, int columns) { this(null, text, columns); } public OverwritableTextField(Document doc, String text, int columns) { super(doc, text, columns); overwriteCaret = new OverwriteCaret(); super.setCaret(overwriting ? overwriteCaret : insertCaret); } public void setKeymap(Keymap map) { if (map == null) { super.setKeymap(null); sharedKeymap = null; return; } if (getKeymap() == null) { if (sharedKeymap == null) { // Switch keymaps. Add extra bindings. removeKeymap(keymapName); sharedKeymap = addKeymap(keymapName, map); loadKeymap(sharedKeymap, bindings, defaultActions); } map = sharedKeymap; } super.setKeymap(map); } public void replaceSelection(String content) { Document doc = getDocument(); if (doc != null) { // If we are not overwriting, just do the // usual insert. Also, if there is a selection, // just overwrite that (and that only). if (overwriting == true && getSelectionStart() == getSelectionEnd()) { // Overwrite and no selection. Remove // the stretch that we will overwrite, // then use the usual code to insert the // new text. int insertPosition = getCaretPosition(); int overwriteLength = doc.getLength() - insertPosition; int length = content.length(); if (overwriteLength > length) { overwriteLength = length; } // Remove the range being overwritten try { doc.remove(insertPosition, overwriteLength); } catch (BadLocationException e) { // Won't happen } } } super.replaceSelection(content); } // Change the global overwriting mode public static void setOverwriting(boolean overwriting) { OverwritableTextField.overwriting = overwriting; } public static boolean isOverwriting() { return overwriting; } // Configuration of the insert caret public void setCaret(Caret caret) { insertCaret = caret; } // Allow configuration of a new // overwrite caret. public void setOverwriteCaret(Caret caret) { overwriteCaret = caret; } public Caret getOverwriteCaret() { return overwriteCaret; } // Caret switching public void processFocusEvent(FocusEvent evt) { if (evt.getID() == FocusEvent.FOCUS_GAINED) { selectCaret(); } super.processFocusEvent(evt); } protected void selectCaret() { // Select the appropriate caret for the // current overwrite mode. Caret newCaret = overwriting ? overwriteCaret : insertCaret; if (newCaret != getCaret()) { Caret caret = getCaret(); int mark = caret.getMark(); int dot = caret.getDot(); caret.setVisible(false); super.setCaret(newCaret); newCaret.setDot(mark); newCaret.moveDot(dot); newCaret.setVisible(true); } } protected Caret overwriteCaret; protected Caret insertCaret; protected static boolean overwriting = true; public static final String toggleOverwriteAction = "toggle-overwrite"; protected static Keymap sharedKeymap; protected static final String keymapName = "OverwriteMap"; protected static final Action[] defaultActions = { new ToggleOverwriteAction() }; protected static JTextComponent.KeyBinding[] bindings = { new JTextComponent.KeyBinding( KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), toggleOverwriteAction) }; // Insert/overwrite toggling action public static class ToggleOverwriteAction extends TextAction { ToggleOverwriteAction() { super(toggleOverwriteAction); } public void actionPerformed(ActionEvent evt) { OverwritableTextField.setOverwriting(!OverwritableTextField .isOverwriting()); JTextComponent target = getFocusedComponent(); if (target instanceof OverwritableTextField) { OverwritableTextField field = (OverwritableTextField) target; field.selectCaret(); } } } public static void main(String[] args) { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception evt) {} JFrame f = new JFrame("Overwrite test"); OverwritableTextField tf = new OverwritableTextField(20); f.getContentPane().add(tf, "North"); tf = new OverwritableTextField(20); f.getContentPane().add(tf, "South"); f.pack(); f.setVisible(true); } } class OverwriteCaret extends DefaultCaret { protected synchronized void damage(Rectangle r) { if (r != null) { try { JTextComponent comp = getComponent(); TextUI mapper = comp.getUI(); Rectangle r2 = mapper.modelToView(comp, getDot() + 1); int width = r2.x - r.x; if (width == 0) { width = MIN_WIDTH; } comp.repaint(r.x, r.y, width, r.height); // Swing 1.1 beta 2 compat this.x = r.x; this.y = r.y; this.width = width; this.height = r.height; } catch (BadLocationException e) { } } } public void paint(Graphics g) { if (isVisible()) { try { JTextComponent comp = getComponent(); TextUI mapper = comp.getUI(); Rectangle r1 = mapper.modelToView(comp, getDot()); Rectangle r2 = mapper.modelToView(comp, getDot() + 1); g = g.create(); g.setColor(comp.getForeground()); g.setXORMode(comp.getBackground()); int width = r2.x - r1.x; if (width == 0) { width = MIN_WIDTH; } g.fillRect(r1.x, r1.y, width, r1.height); g.dispose(); } catch (BadLocationException e) { } } } protected static final int MIN_WIDTH = 8; }