JTextComponent.java [plain text]
package javax.swing.text;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.InputMethodListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleStateSet;
import javax.accessibility.AccessibleText;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.Scrollable;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TextUI;
public abstract class JTextComponent extends JComponent
implements Scrollable, Accessible
{
public class AccessibleJTextComponent extends AccessibleJComponent
implements AccessibleText, CaretListener, DocumentListener
{
private static final long serialVersionUID = 7664188944091413696L;
public AccessibleJTextComponent()
{
}
public int getCaretPosition()
{
return 0; }
public String getSelectedText()
{
return null; }
public int getSelectionStart()
{
return 0; }
public int getSelectionEnd()
{
return 0; }
public void caretUpdate(CaretEvent value0)
{
}
public AccessibleStateSet getAccessibleStateSet()
{
return null; }
public AccessibleRole getAccessibleRole()
{
return null; }
public AccessibleText getAccessibleText()
{
return null; }
public void insertUpdate(DocumentEvent value0)
{
}
public void removeUpdate(DocumentEvent value0)
{
}
public void changedUpdate(DocumentEvent value0)
{
}
public int getIndexAtPoint(Point value0)
{
return 0; }
Rectangle getRootEditorRect()
{
return null;
}
public Rectangle getCharacterBounds(int value0)
{
return null; }
public int getCharCount()
{
return 0; }
public AttributeSet getCharacterAttribute(int value0)
{
return null; }
public String getAtIndex(int value0, int value1)
{
return null; }
public String getAfterIndex(int value0, int value1)
{
return null; }
public String getBeforeIndex(int value0, int value1)
{
return null; }
}
public static class KeyBinding
{
public KeyStroke key;
public String actionName;
public KeyBinding(KeyStroke key, String actionName)
{
this.key = key;
this.actionName = actionName;
}
}
private class KeymapWrapper extends InputMap
{
Keymap map;
public KeymapWrapper(Keymap k)
{
map = k;
}
public int size()
{
return map.getBoundKeyStrokes().length + super.size();
}
public Object get(KeyStroke ks)
{
Action mapped = null;
Keymap m = map;
while(mapped == null && m != null)
{
mapped = m.getAction(ks);
if (mapped == null && ks.getKeyEventType() == KeyEvent.KEY_TYPED)
mapped = m.getDefaultAction();
if (mapped == null)
m = m.getResolveParent();
}
if (mapped == null)
return super.get(ks);
else
return mapped;
}
public KeyStroke[] keys()
{
KeyStroke[] superKeys = super.keys();
KeyStroke[] mapKeys = map.getBoundKeyStrokes();
KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length];
for (int i = 0; i < superKeys.length; ++i)
bothKeys[i] = superKeys[i];
for (int i = 0; i < mapKeys.length; ++i)
bothKeys[i + superKeys.length] = mapKeys[i];
return bothKeys;
}
public KeyStroke[] allKeys()
{
KeyStroke[] superKeys = super.allKeys();
KeyStroke[] mapKeys = map.getBoundKeyStrokes();
KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length];
for (int i = 0; i < superKeys.length; ++i)
bothKeys[i] = superKeys[i];
for (int i = 0; i < mapKeys.length; ++i)
bothKeys[i + superKeys.length] = mapKeys[i];
return bothKeys;
}
}
private class KeymapActionMap extends ActionMap
{
Keymap map;
public KeymapActionMap(Keymap k)
{
map = k;
}
public Action get(Object cmd)
{
if (cmd instanceof Action)
return (Action) cmd;
else
return super.get(cmd);
}
public int size()
{
return map.getBoundKeyStrokes().length + super.size();
}
public Object[] keys()
{
Object[] superKeys = super.keys();
Object[] mapKeys = map.getBoundKeyStrokes();
Object[] bothKeys = new Object[superKeys.length + mapKeys.length];
for (int i = 0; i < superKeys.length; ++i)
bothKeys[i] = superKeys[i];
for (int i = 0; i < mapKeys.length; ++i)
bothKeys[i + superKeys.length] = mapKeys[i];
return bothKeys;
}
public Object[] allKeys()
{
Object[] superKeys = super.allKeys();
Object[] mapKeys = map.getBoundKeyStrokes();
Object[] bothKeys = new Object[superKeys.length + mapKeys.length];
for (int i = 0; i < superKeys.length; ++i)
bothKeys[i] = superKeys[i];
for (int i = 0; i < mapKeys.length; ++i)
bothKeys[i + superKeys.length] = mapKeys[i];
return bothKeys;
}
}
static class DefaultKeymap implements Keymap
{
String name;
Keymap parent;
Hashtable map;
Action defaultAction;
public DefaultKeymap(String name)
{
this.name = name;
this.map = new Hashtable();
}
public void addActionForKeyStroke(KeyStroke key, Action a)
{
map.put(key, a);
}
public Action getAction(KeyStroke key)
{
if (map.containsKey(key))
return (Action) map.get(key);
else if (parent != null)
return parent.getAction(key);
else
return null;
}
public Action[] getBoundActions()
{
Action [] ret = new Action[map.size()];
Enumeration e = map.elements();
int i = 0;
while (e.hasMoreElements())
{
ret[i++] = (Action) e.nextElement();
}
return ret;
}
public KeyStroke[] getBoundKeyStrokes()
{
KeyStroke [] ret = new KeyStroke[map.size()];
Enumeration e = map.keys();
int i = 0;
while (e.hasMoreElements())
{
ret[i++] = (KeyStroke) e.nextElement();
}
return ret;
}
public Action getDefaultAction()
{
return defaultAction;
}
public KeyStroke[] getKeyStrokesForAction(Action a)
{
int i = 0;
Enumeration e = map.keys();
while (e.hasMoreElements())
{
if (map.get(e.nextElement()).equals(a))
++i;
}
KeyStroke [] ret = new KeyStroke[i];
i = 0;
e = map.keys();
while (e.hasMoreElements())
{
KeyStroke k = (KeyStroke) e.nextElement();
if (map.get(k).equals(a))
ret[i++] = k;
}
return ret;
}
public String getName()
{
return name;
}
public Keymap getResolveParent()
{
return parent;
}
public boolean isLocallyDefined(KeyStroke key)
{
return map.containsKey(key);
}
public void removeBindings()
{
map.clear();
}
public void removeKeyStrokeBinding(KeyStroke key)
{
map.remove(key);
}
public void setDefaultAction(Action a)
{
defaultAction = a;
}
public void setResolveParent(Keymap p)
{
parent = p;
}
}
class DefaultTransferHandler
extends TransferHandler
{
public boolean canImport(JComponent component, DataFlavor[] flavors)
{
JTextComponent textComponent = (JTextComponent) component;
if (! (textComponent.isEnabled()
&& textComponent.isEditable()
&& flavors != null))
return false;
for (int i = 0; i < flavors.length; ++i)
if (flavors[i].equals(DataFlavor.stringFlavor))
return true;
return false;
}
public void exportToClipboard(JComponent component, Clipboard clipboard,
int action)
{
JTextComponent textComponent = (JTextComponent) component;
int start = textComponent.getSelectionStart();
int end = textComponent.getSelectionEnd();
if (start == end)
return;
try
{
String data = textComponent.getDocument().getText(start, end);
StringSelection selection = new StringSelection(data);
clipboard.setContents(selection, null);
if (action == MOVE)
doc.remove(start, end - start);
}
catch (BadLocationException e)
{
}
}
public int getSourceActions()
{
return NONE;
}
public boolean importData(JComponent component, Transferable transferable)
{
DataFlavor flavor = null;
DataFlavor[] flavors = transferable.getTransferDataFlavors();
if (flavors == null)
return false;
for (int i = 0; i < flavors.length; ++i)
if (flavors[i].equals(DataFlavor.stringFlavor))
flavor = flavors[i];
if (flavor == null)
return false;
try
{
JTextComponent textComponent = (JTextComponent) component;
String data = (String) transferable.getTransferData(flavor);
textComponent.replaceSelection(data);
return true;
}
catch (IOException e)
{
}
catch (UnsupportedFlavorException e)
{
}
return false;
}
}
private static final long serialVersionUID = -8796518220218978795L;
public static final String DEFAULT_KEYMAP = "default";
public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
private static DefaultTransferHandler defaultTransferHandler;
private static Hashtable keymaps = new Hashtable();
private Keymap keymap;
private char focusAccelerator = '\0';
private NavigationFilter navigationFilter;
public static Keymap getKeymap(String n)
{
return (Keymap) keymaps.get(n);
}
public static Keymap removeKeymap(String n)
{
Keymap km = (Keymap) keymaps.get(n);
keymaps.remove(n);
return km;
}
public static Keymap addKeymap(String n, Keymap parent)
{
Keymap k = new DefaultKeymap(n);
k.setResolveParent(parent);
if (n != null)
keymaps.put(n, k);
return k;
}
public Keymap getKeymap()
{
return keymap;
}
public void setKeymap(Keymap k)
{
KeymapWrapper kw = (k == null ? null : new KeymapWrapper(k));
InputMap childInputMap = getInputMap(JComponent.WHEN_FOCUSED);
if (childInputMap == null)
setInputMap(JComponent.WHEN_FOCUSED, kw);
else
{
while (childInputMap.getParent() != null
&& !(childInputMap.getParent() instanceof KeymapWrapper)
&& !(childInputMap.getParent() instanceof InputMapUIResource))
childInputMap = childInputMap.getParent();
if (childInputMap.getParent() == null)
childInputMap.setParent(kw);
else if (childInputMap.getParent() instanceof KeymapWrapper)
{
if (kw == null)
childInputMap.setParent(childInputMap.getParent().getParent());
else
{
kw.setParent(childInputMap.getParent().getParent());
childInputMap.setParent(kw);
}
}
else if (childInputMap.getParent() instanceof InputMapUIResource)
{
if (kw != null)
{
kw.setParent(childInputMap.getParent());
childInputMap.setParent(kw);
}
}
}
KeymapActionMap kam = (k == null ? null : new KeymapActionMap(k));
ActionMap childActionMap = getActionMap();
if (childActionMap == null)
setActionMap(kam);
else
{
while (childActionMap.getParent() != null
&& !(childActionMap.getParent() instanceof KeymapActionMap)
&& !(childActionMap.getParent() instanceof ActionMapUIResource))
childActionMap = childActionMap.getParent();
if (childActionMap.getParent() == null)
childActionMap.setParent(kam);
else if (childActionMap.getParent() instanceof KeymapActionMap)
{
if (kam == null)
childActionMap.setParent(childActionMap.getParent().getParent());
else
{
kam.setParent(childActionMap.getParent().getParent());
childActionMap.setParent(kam);
}
}
else if (childActionMap.getParent() instanceof ActionMapUIResource)
{
if (kam != null)
{
kam.setParent(childActionMap.getParent());
childActionMap.setParent(kam);
}
}
}
Keymap old = keymap;
keymap = k;
firePropertyChange("keymap", old, k);
}
public static void loadKeymap(Keymap map,
JTextComponent.KeyBinding[] bindings,
Action[] actions)
{
Hashtable acts = new Hashtable(actions.length);
for (int i = 0; i < actions.length; ++i)
acts.put(actions[i].getValue(Action.NAME), actions[i]);
for (int i = 0; i < bindings.length; ++i)
if (acts.containsKey(bindings[i].actionName))
map.addActionForKeyStroke(bindings[i].key, (Action) acts.get(bindings[i].actionName));
}
public Action[] getActions()
{
return getUI().getEditorKit(this).getActions();
}
private Document doc;
private Caret caret;
private Highlighter highlighter;
private Color caretColor;
private Color disabledTextColor;
private Color selectedTextColor;
private Color selectionColor;
private boolean editable;
private Insets margin;
private boolean dragEnabled;
public JTextComponent()
{
Keymap defkeymap = getKeymap(DEFAULT_KEYMAP);
boolean creatingKeymap = false;
if (defkeymap == null)
{
defkeymap = addKeymap(DEFAULT_KEYMAP, null);
defkeymap.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction());
creatingKeymap = true;
}
setFocusable(true);
enableEvents(AWTEvent.KEY_EVENT_MASK);
updateUI();
if (creatingKeymap)
loadKeymap(defkeymap,
new KeyBinding[] {
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
DefaultEditorKit.backwardAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
DefaultEditorKit.forwardAction),
new KeyBinding(KeyStroke.getKeyStroke("typed \b"),
DefaultEditorKit.deletePrevCharAction),
new KeyBinding(KeyStroke.getKeyStroke("typed \u007f"),
DefaultEditorKit.deleteNextCharAction)
},
getActions());
}
public void setDocument(Document newDoc)
{
Document oldDoc = doc;
doc = newDoc;
firePropertyChange("document", oldDoc, newDoc);
revalidate();
repaint();
}
public Document getDocument()
{
return doc;
}
public AccessibleContext getAccessibleContext()
{
return null;
}
public void setMargin(Insets m)
{
margin = m;
}
public Insets getMargin()
{
return margin;
}
public void setText(String text)
{
try
{
doc.remove(0, doc.getLength());
doc.insertString(0, text, null);
}
catch (BadLocationException e)
{
}
}
public String getText()
{
if (doc == null)
return null;
try
{
return doc.getText(0, doc.getLength());
}
catch (BadLocationException e)
{
return "";
}
}
public String getText(int offset, int length)
throws BadLocationException
{
return getDocument().getText(offset, length);
}
public String getSelectedText()
{
try
{
return doc.getText(getSelectionStart(), getSelectionEnd());
}
catch (BadLocationException e)
{
return null;
}
}
public String getUIClassID()
{
return "TextComponentUI";
}
protected String paramString()
{
return "JTextComponent";
}
public TextUI getUI()
{
return (TextUI) ui;
}
public void setUI(TextUI newUI)
{
super.setUI(newUI);
}
public void updateUI()
{
setUI((TextUI) UIManager.getUI(this));
}
public Dimension getPreferredScrollableViewportSize()
{
return null;
}
public int getScrollableUnitIncrement(Rectangle visible, int orientation,
int direction)
{
return 0;
}
public int getScrollableBlockIncrement(Rectangle visible, int orientation,
int direction)
{
return 0;
}
public boolean isEditable()
{
return editable;
}
public void setEditable(boolean newValue)
{
if (editable == newValue)
return;
boolean oldValue = editable;
editable = newValue;
firePropertyChange("editable", oldValue, newValue);
}
public Caret getCaret()
{
return caret;
}
public void setCaret(Caret newCaret)
{
if (caret != null)
caret.deinstall(this);
Caret oldCaret = caret;
caret = newCaret;
if (caret != null)
caret.install(this);
firePropertyChange("caret", oldCaret, newCaret);
}
public Color getCaretColor()
{
return caretColor;
}
public void setCaretColor(Color newColor)
{
Color oldCaretColor = caretColor;
caretColor = newColor;
firePropertyChange("caretColor", oldCaretColor, newColor);
}
public Color getDisabledTextColor()
{
return disabledTextColor;
}
public void setDisabledTextColor(Color newColor)
{
Color oldColor = disabledTextColor;
disabledTextColor = newColor;
firePropertyChange("disabledTextColor", oldColor, newColor);
}
public Color getSelectedTextColor()
{
return selectedTextColor;
}
public void setSelectedTextColor(Color newColor)
{
Color oldColor = selectedTextColor;
selectedTextColor = newColor;
firePropertyChange("selectedTextColor", oldColor, newColor);
}
public Color getSelectionColor()
{
return selectionColor;
}
public void setSelectionColor(Color newColor)
{
Color oldColor = selectionColor;
selectionColor = newColor;
firePropertyChange("selectionColor", oldColor, newColor);
}
public int getCaretPosition()
{
return caret.getDot();
}
public void setCaretPosition(int position)
{
if (doc == null)
return;
if (position < 0 || position > doc.getLength())
throw new IllegalArgumentException();
caret.setDot(position);
}
public void moveCaretPosition(int position)
{
if (doc == null)
return;
if (position < 0 || position > doc.getLength())
throw new IllegalArgumentException();
caret.moveDot(position);
}
public Highlighter getHighlighter()
{
return highlighter;
}
public void setHighlighter(Highlighter newHighlighter)
{
if (highlighter != null)
highlighter.deinstall(this);
Highlighter oldHighlighter = highlighter;
highlighter = newHighlighter;
if (highlighter != null)
highlighter.install(this);
firePropertyChange("highlighter", oldHighlighter, newHighlighter);
}
public int getSelectionStart()
{
return Math.min(caret.getDot(), caret.getMark());
}
public void setSelectionStart(int start)
{
select(start, getSelectionEnd());
}
public int getSelectionEnd()
{
return Math.max(caret.getDot(), caret.getMark());
}
public void setSelectionEnd(int end)
{
select(getSelectionStart(), end);
}
public void select(int start, int end)
{
int length = doc.getLength();
start = Math.max(start, 0);
start = Math.min(start, length);
end = Math.max(end, 0);
end = Math.min(end, length);
setCaretPosition(start);
moveCaretPosition(end);
}
public void selectAll()
{
select(0, doc.getLength());
}
public synchronized void replaceSelection(String content)
{
int dot = caret.getDot();
int mark = caret.getMark();
if (content == null)
{
caret.setDot(dot);
return;
}
try
{
int start = getSelectionStart();
int end = getSelectionEnd();
if (dot != mark)
doc.remove(start, end - start);
doc.insertString(start, content, null);
setCaretPosition(start + content.length());
}
catch (BadLocationException e)
{
}
}
public boolean getScrollableTracksViewportHeight()
{
if (getParent() instanceof JViewport)
return ((JViewport) getParent()).getHeight() > getPreferredSize().height;
return false;
}
public boolean getScrollableTracksViewportWidth()
{
if (getParent() instanceof JViewport)
return ((JViewport) getParent()).getWidth() > getPreferredSize().width;
return false;
}
public void addCaretListener(CaretListener listener)
{
listenerList.add(CaretListener.class, listener);
}
public void removeCaretListener(CaretListener listener)
{
listenerList.remove(CaretListener.class, listener);
}
public CaretListener[] getCaretListeners()
{
return (CaretListener[]) getListeners(CaretListener.class);
}
protected void fireCaretUpdate(CaretEvent event)
{
CaretListener[] listeners = getCaretListeners();
for (int index = 0; index < listeners.length; ++index)
listeners[index].caretUpdate(event);
}
public void addInputMethodListener(InputMethodListener listener)
{
listenerList.add(InputMethodListener.class, listener);
}
public void removeInputMethodListener(InputMethodListener listener)
{
listenerList.remove(InputMethodListener.class, listener);
}
public InputMethodListener[] getInputMethodListeners()
{
return (InputMethodListener[]) getListeners(InputMethodListener.class);
}
public Rectangle modelToView(int position) throws BadLocationException
{
return getUI().modelToView(this, position);
}
public boolean getDragEnabled()
{
return dragEnabled;
}
public void setDragEnabled(boolean enabled)
{
dragEnabled = enabled;
}
public int viewToModel(Point pt)
{
return getUI().viewToModel(this, pt);
}
public void copy()
{
doTransferAction("copy", TransferHandler.getCopyAction());
}
public void cut()
{
doTransferAction("cut", TransferHandler.getCutAction());
}
public void paste()
{
doTransferAction("paste", TransferHandler.getPasteAction());
}
private void doTransferAction(String name, Action action)
{
if (getTransferHandler() == null)
{
if (defaultTransferHandler == null)
defaultTransferHandler = new DefaultTransferHandler();
setTransferHandler(defaultTransferHandler);
}
ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
action.getValue(Action.NAME).toString());
action.actionPerformed(event);
}
public void setFocusAccelerator(char newKey)
{
if (focusAccelerator == newKey)
return;
char oldKey = focusAccelerator;
focusAccelerator = newKey;
firePropertyChange(FOCUS_ACCELERATOR_KEY, oldKey, newKey);
}
public char getFocusAccelerator()
{
return focusAccelerator;
}
public NavigationFilter getNavigationFilter()
{
return navigationFilter;
}
public void setNavigationFilter(NavigationFilter filter)
{
navigationFilter = filter;
}
}