| /* JTextComponent.java -- |
| Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package javax.swing.text; |
| |
| import gnu.classpath.NotImplementedException; |
| |
| import java.awt.AWTEvent; |
| import java.awt.Color; |
| import java.awt.Container; |
| 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.awt.event.MouseEvent; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.Writer; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| |
| import javax.accessibility.Accessible; |
| import javax.accessibility.AccessibleAction; |
| import javax.accessibility.AccessibleContext; |
| import javax.accessibility.AccessibleEditableText; |
| 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.SwingConstants; |
| 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 |
| { |
| /** |
| * AccessibleJTextComponent implements accessibility hooks for |
| * JTextComponent. It allows an accessibility driver to read and |
| * manipulate the text component's contents as well as update UI |
| * elements such as the caret. |
| */ |
| public class AccessibleJTextComponent extends AccessibleJComponent implements |
| AccessibleText, CaretListener, DocumentListener, AccessibleAction, |
| AccessibleEditableText |
| { |
| private static final long serialVersionUID = 7664188944091413696L; |
| |
| /** |
| * The caret's offset. |
| */ |
| int dot = 0; |
| |
| /** |
| * The current JTextComponent. |
| */ |
| JTextComponent textComp = JTextComponent.this; |
| |
| /** |
| * Construct an AccessibleJTextComponent. |
| */ |
| public AccessibleJTextComponent() |
| { |
| super(); |
| textComp.addCaretListener(this); |
| } |
| |
| /** |
| * Retrieve the current caret position. The index of the first |
| * caret position is 0. |
| * |
| * @return caret position |
| */ |
| public int getCaretPosition() |
| { |
| dot = textComp.getCaretPosition(); |
| return dot; |
| } |
| |
| /** |
| * Retrieve the current text selection. If no text is selected |
| * this method returns null. |
| * |
| * @return the currently selected text or null |
| */ |
| public String getSelectedText() |
| { |
| return textComp.getSelectedText(); |
| } |
| |
| /** |
| * Retrieve the index of the first character in the current text |
| * selection. If there is no text in the text component, this |
| * method returns 0. If there is text in the text component, but |
| * there is no selection, this method returns the current caret |
| * position. |
| * |
| * @return the index of the first character in the selection, the |
| * current caret position or 0 |
| */ |
| public int getSelectionStart() |
| { |
| if (getSelectedText() == null || (textComp.getText().equals(""))) |
| return 0; |
| return textComp.getSelectionStart(); |
| } |
| |
| /** |
| * Retrieve the index of the last character in the current text |
| * selection. If there is no text in the text component, this |
| * method returns 0. If there is text in the text component, but |
| * there is no selection, this method returns the current caret |
| * position. |
| * |
| * @return the index of the last character in the selection, the |
| * current caret position or 0 |
| */ |
| public int getSelectionEnd() |
| { |
| if (getSelectedText() == null || (textComp.getText().equals(""))) |
| return 0; |
| return textComp.getSelectionEnd(); |
| } |
| |
| /** |
| * Handle a change in the caret position and fire any applicable |
| * property change events. |
| * |
| * @param e - the caret update event |
| */ |
| public void caretUpdate(CaretEvent e) |
| throws NotImplementedException |
| { |
| // TODO: fire appropriate event. |
| dot = e.getDot(); |
| } |
| |
| /** |
| * Retreive the accessible state set of this component. |
| * |
| * @return the accessible state set of this component |
| */ |
| public AccessibleStateSet getAccessibleStateSet() |
| throws NotImplementedException |
| { |
| AccessibleStateSet state = super.getAccessibleStateSet(); |
| // TODO: Figure out what state must be added here to the super's state. |
| return state; |
| } |
| |
| /** |
| * Retrieve the accessible role of this component. |
| * |
| * @return the accessible role of this component |
| * |
| * @see AccessibleRole |
| */ |
| public AccessibleRole getAccessibleRole() |
| { |
| return AccessibleRole.TEXT; |
| } |
| |
| /** |
| * Retrieve an AccessibleEditableText object that controls this |
| * text component. |
| * |
| * @return this |
| */ |
| public AccessibleEditableText getAccessibleEditableText() |
| { |
| return this; |
| } |
| |
| /** |
| * Retrieve an AccessibleText object that controls this text |
| * component. |
| * |
| * @return this |
| * |
| * @see AccessibleText |
| */ |
| public AccessibleText getAccessibleText() |
| { |
| return this; |
| } |
| |
| /** |
| * Handle a text insertion event and fire an |
| * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change |
| * event. |
| * |
| * @param e - the insertion event |
| */ |
| public void insertUpdate(DocumentEvent e) |
| throws NotImplementedException |
| { |
| // TODO |
| } |
| |
| /** |
| * Handle a text removal event and fire an |
| * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change |
| * event. |
| * |
| * @param e - the removal event |
| */ |
| public void removeUpdate(DocumentEvent e) |
| throws NotImplementedException |
| { |
| // TODO |
| } |
| |
| /** |
| * Handle a text change event and fire an |
| * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change |
| * event. |
| * |
| * @param e - text change event |
| */ |
| public void changedUpdate(DocumentEvent e) |
| throws NotImplementedException |
| { |
| // TODO |
| } |
| |
| /** |
| * Get the index of the character at the given point, in component |
| * pixel co-ordinates. If the point argument is invalid this |
| * method returns -1. |
| * |
| * @param p - a point in component pixel co-ordinates |
| * |
| * @return a character index, or -1 |
| */ |
| public int getIndexAtPoint(Point p) |
| throws NotImplementedException |
| { |
| return 0; // TODO |
| } |
| |
| /** |
| * Calculate the bounding box of the character at the given index. |
| * The returned x and y co-ordinates are relative to this text |
| * component's top-left corner. If the index is invalid this |
| * method returns null. |
| * |
| * @param index - the character index |
| * |
| * @return a character's bounding box, or null |
| */ |
| public Rectangle getCharacterBounds(int index) |
| throws NotImplementedException |
| { |
| return null; // TODO |
| } |
| |
| /** |
| * Return the length of the text in this text component. |
| * |
| * @return a character length |
| */ |
| public int getCharCount() |
| { |
| return textComp.getText().length(); |
| } |
| |
| /** |
| * Gets the character attributes of the character at index. If |
| * the index is out of bounds, null is returned. |
| * |
| * @param index - index of the character |
| * |
| * @return the character's attributes |
| */ |
| public AttributeSet getCharacterAttribute(int index) |
| throws NotImplementedException |
| { |
| return null; // TODO |
| } |
| |
| /** |
| * Gets the text located at index. null is returned if the index |
| * or part is invalid. |
| * |
| * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} |
| * @param index - index of the part |
| * |
| * @return the part of text at that index, or null |
| */ |
| public String getAtIndex(int part, int index) |
| throws NotImplementedException |
| { |
| return null; // TODO |
| } |
| |
| /** |
| * Gets the text located after index. null is returned if the index |
| * or part is invalid. |
| * |
| * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} |
| * @param index - index after the part |
| * |
| * @return the part of text after that index, or null |
| */ |
| public String getAfterIndex(int part, int index) |
| throws NotImplementedException |
| { |
| return null; // TODO |
| } |
| |
| /** |
| * Gets the text located before index. null is returned if the index |
| * or part is invalid. |
| * |
| * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} |
| * @param index - index before the part |
| * |
| * @return the part of text before that index, or null |
| */ |
| public String getBeforeIndex(int part, int index) |
| throws NotImplementedException |
| { |
| return null; // TODO |
| } |
| |
| /** |
| * Returns the number of actions for this object. The zero-th |
| * object represents the default action. |
| * |
| * @return the number of actions (0-based). |
| */ |
| public int getAccessibleActionCount() |
| throws NotImplementedException |
| { |
| return 0; // TODO |
| } |
| |
| /** |
| * Returns the description of the i-th action. Null is returned if |
| * i is out of bounds. |
| * |
| * @param i - the action to get the description for |
| * |
| * @return description of the i-th action |
| */ |
| public String getAccessibleActionDescription(int i) |
| throws NotImplementedException |
| { |
| // TODO: Not implemented fully |
| return super.getAccessibleDescription(); |
| } |
| |
| /** |
| * Performs the i-th action. Nothing happens if i is |
| * out of bounds. |
| * |
| * @param i - the action to perform |
| * |
| * @return true if the action was performed successfully |
| */ |
| public boolean doAccessibleAction(int i) |
| throws NotImplementedException |
| { |
| return false; // TODO |
| } |
| |
| /** |
| * Sets the text contents. |
| * |
| * @param s - the new text contents. |
| */ |
| public void setTextContents(String s) |
| throws NotImplementedException |
| { |
| // TODO |
| } |
| |
| /** |
| * Inserts the text at the given index. |
| * |
| * @param index - the index to insert the new text at. |
| * @param s - the new text |
| */ |
| public void insertTextAtIndex(int index, String s) |
| throws NotImplementedException |
| { |
| replaceText(index, index, s); |
| } |
| |
| /** |
| * Gets the text between two indexes. |
| * |
| * @param start - the starting index (inclusive) |
| * @param end - the ending index (exclusive) |
| */ |
| public String getTextRange(int start, int end) |
| { |
| try |
| { |
| return textComp.getText(start, end - start); |
| } |
| catch (BadLocationException ble) |
| { |
| return ""; |
| } |
| } |
| |
| /** |
| * Deletes the text between two indexes. |
| * |
| * @param start - the starting index (inclusive) |
| * @param end - the ending index (exclusive) |
| */ |
| public void delete(int start, int end) |
| { |
| replaceText(start, end, ""); |
| } |
| |
| /** |
| * Cuts the text between two indexes. The text is put |
| * into the system clipboard. |
| * |
| * @param start - the starting index (inclusive) |
| * @param end - the ending index (exclusive) |
| */ |
| public void cut(int start, int end) |
| { |
| textComp.select(start, end); |
| textComp.cut(); |
| } |
| |
| /** |
| * Pastes the text from the system clipboard to the given index. |
| * |
| * @param start - the starting index |
| */ |
| public void paste(int start) |
| { |
| textComp.setCaretPosition(start); |
| textComp.paste(); |
| } |
| |
| /** |
| * Replaces the text between two indexes with the given text. |
| * |
| * |
| * @param start - the starting index (inclusive) |
| * @param end - the ending index (exclusive) |
| * @param s - the text to paste |
| */ |
| public void replaceText(int start, int end, String s) |
| { |
| textComp.select(start, end); |
| textComp.replaceSelection(s); |
| } |
| |
| /** |
| * Selects the text between two indexes. |
| * |
| * @param start - the starting index (inclusive) |
| * @param end - the ending index (exclusive) |
| */ |
| public void selectText(int start, int end) |
| { |
| textComp.select(start, end); |
| } |
| |
| /** |
| * Sets the attributes of all the text between two indexes. |
| * |
| * @param start - the starting index (inclusive) |
| * @param end - the ending index (exclusive) |
| * @param s - the new attribute set for the text in the range |
| */ |
| public void setAttributes(int start, int end, AttributeSet s) |
| throws NotImplementedException |
| { |
| // TODO |
| } |
| } |
| |
| public static class KeyBinding |
| { |
| public KeyStroke key; |
| public String actionName; |
| |
| /** |
| * Creates a new <code>KeyBinding</code> instance. |
| * |
| * @param key a <code>KeyStroke</code> value |
| * @param actionName a <code>String</code> value |
| */ |
| public KeyBinding(KeyStroke key, String actionName) |
| { |
| this.key = key; |
| this.actionName = actionName; |
| } |
| } |
| |
| /** |
| * According to <a |
| * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">this |
| * report</a>, a pair of private classes wraps a {@link |
| * javax.swing.text.Keymap} in the new {@link InputMap} / {@link |
| * ActionMap} interfaces, such that old Keymap-using code can make use of |
| * the new framework. |
| * |
| * <p>A little bit of experimentation with these classes reveals the following |
| * structure: |
| * |
| * <ul> |
| * |
| * <li>KeymapWrapper extends {@link InputMap} and holds a reference to |
| * the underlying {@link Keymap}.</li> |
| * |
| * <li>KeymapWrapper maps {@link KeyStroke} objects to {@link Action} |
| * objects, by delegation to the underlying {@link Keymap}.</li> |
| * |
| * <li>KeymapActionMap extends {@link ActionMap} also holds a reference to |
| * the underlying {@link Keymap} but only appears to use it for listing |
| * its keys. </li> |
| * |
| * <li>KeymapActionMap maps all {@link Action} objects to |
| * <em>themselves</em>, whether they exist in the underlying {@link |
| * Keymap} or not, and passes other objects to the parent {@link |
| * ActionMap} for resolving. |
| * |
| * </ul> |
| */ |
| |
| 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(); |
| int skl = 0; |
| int mkl = 0; |
| if (superKeys != null) |
| skl = superKeys.length; |
| if (mapKeys != null) |
| mkl = mapKeys.length; |
| KeyStroke[] bothKeys = new KeyStroke[skl + mkl]; |
| for (int i = 0; i < skl; ++i) |
| bothKeys[i] = superKeys[i]; |
| for (int i = 0; i < mkl; ++i) |
| bothKeys[i + skl] = 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); |
| } |
| |
| /** |
| * Looks up a KeyStroke either in the current map or the parent Keymap; |
| * does <em>not</em> return the default action if lookup fails. |
| * |
| * @param key The KeyStroke to look up an Action for. |
| * |
| * @return The mapping for <code>key</code>, or <code>null</code> |
| * if no mapping exists in this Keymap or any of its parents. |
| */ |
| 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 |
| { |
| // Copy text to clipboard. |
| String data = textComponent.getDocument().getText(start, end); |
| StringSelection selection = new StringSelection(data); |
| clipboard.setContents(selection, null); |
| |
| // Delete selected text on cut action. |
| if (action == MOVE) |
| doc.remove(start, end - start); |
| } |
| catch (BadLocationException e) |
| { |
| // Ignore this and do nothing. |
| } |
| } |
| |
| 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) |
| { |
| // Ignored. |
| } |
| catch (UnsupportedFlavorException e) |
| { |
| // Ignored. |
| } |
| |
| 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; |
| |
| /** |
| * Get a Keymap from the global keymap table, by name. |
| * |
| * @param n The name of the Keymap to look up |
| * |
| * @return A Keymap associated with the provided name, or |
| * <code>null</code> if no such Keymap exists |
| * |
| * @see #addKeymap |
| * @see #removeKeymap |
| * @see #keymaps |
| */ |
| public static Keymap getKeymap(String n) |
| { |
| return (Keymap) keymaps.get(n); |
| } |
| |
| /** |
| * Remove a Keymap from the global Keymap table, by name. |
| * |
| * @param n The name of the Keymap to remove |
| * |
| * @return The keymap removed from the global table |
| * |
| * @see #addKeymap |
| * @see #getKeymap() |
| * @see #keymaps |
| */ |
| public static Keymap removeKeymap(String n) |
| { |
| Keymap km = (Keymap) keymaps.get(n); |
| keymaps.remove(n); |
| return km; |
| } |
| |
| /** |
| * Create a new Keymap with a specific name and parent, and add the new |
| * Keymap to the global keymap table. The name may be <code>null</code>, |
| * in which case the new Keymap will <em>not</em> be added to the global |
| * Keymap table. The parent may also be <code>null</code>, which is |
| * harmless. |
| * |
| * @param n The name of the new Keymap, or <code>null</code> |
| * @param parent The parent of the new Keymap, or <code>null</code> |
| * |
| * @return The newly created Keymap |
| * |
| * @see #removeKeymap |
| * @see #getKeymap() |
| * @see #keymaps |
| */ |
| 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; |
| } |
| |
| /** |
| * Get the current Keymap of this component. |
| * |
| * @return The component's current Keymap |
| * |
| * @see #setKeymap |
| * @see #keymap |
| */ |
| public Keymap getKeymap() |
| { |
| return keymap; |
| } |
| |
| /** |
| * Set the current Keymap of this component, installing appropriate |
| * {@link KeymapWrapper} and {@link KeymapActionMap} objects in the |
| * {@link InputMap} and {@link ActionMap} parent chains, respectively, |
| * and fire a property change event with name <code>"keymap"</code>. |
| * |
| * @see #getKeymap() |
| * @see #keymap |
| */ |
| public void setKeymap(Keymap k) |
| { |
| |
| // phase 1: replace the KeymapWrapper entry in the InputMap chain. |
| // the goal here is to always maintain the following ordering: |
| // |
| // [InputMap]? -> [KeymapWrapper]? -> [InputMapUIResource]* |
| // |
| // that is to say, component-specific InputMaps need to remain children |
| // of Keymaps, and Keymaps need to remain children of UI-installed |
| // InputMaps (and the order of each group needs to be preserved, of |
| // course). |
| |
| 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(); |
| |
| // option 1: there is nobody to replace at the end of the chain |
| if (childInputMap.getParent() == null) |
| childInputMap.setParent(kw); |
| |
| // option 2: there is already a KeymapWrapper in the chain which |
| // needs replacing (possibly with its own parents, possibly without) |
| else if (childInputMap.getParent() instanceof KeymapWrapper) |
| { |
| if (kw == null) |
| childInputMap.setParent(childInputMap.getParent().getParent()); |
| else |
| { |
| kw.setParent(childInputMap.getParent().getParent()); |
| childInputMap.setParent(kw); |
| } |
| } |
| |
| // option 3: there is an InputMapUIResource in the chain, which marks |
| // the place where we need to stop and insert ourselves |
| else if (childInputMap.getParent() instanceof InputMapUIResource) |
| { |
| if (kw != null) |
| { |
| kw.setParent(childInputMap.getParent()); |
| childInputMap.setParent(kw); |
| } |
| } |
| } |
| |
| // phase 2: replace the KeymapActionMap entry in the ActionMap chain |
| |
| 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(); |
| |
| // option 1: there is nobody to replace at the end of the chain |
| if (childActionMap.getParent() == null) |
| childActionMap.setParent(kam); |
| |
| // option 2: there is already a KeymapActionMap in the chain which |
| // needs replacing (possibly with its own parents, possibly without) |
| else if (childActionMap.getParent() instanceof KeymapActionMap) |
| { |
| if (kam == null) |
| childActionMap.setParent(childActionMap.getParent().getParent()); |
| else |
| { |
| kam.setParent(childActionMap.getParent().getParent()); |
| childActionMap.setParent(kam); |
| } |
| } |
| |
| // option 3: there is an ActionMapUIResource in the chain, which marks |
| // the place where we need to stop and insert ourselves |
| else if (childActionMap.getParent() instanceof ActionMapUIResource) |
| { |
| if (kam != null) |
| { |
| kam.setParent(childActionMap.getParent()); |
| childActionMap.setParent(kam); |
| } |
| } |
| } |
| |
| // phase 3: update the explicit keymap field |
| |
| Keymap old = keymap; |
| keymap = k; |
| firePropertyChange("keymap", old, k); |
| } |
| |
| /** |
| * Resolves a set of bindings against a set of actions and inserts the |
| * results into a {@link Keymap}. Specifically, for each provided binding |
| * <code>b</code>, if there exists a provided action <code>a</code> such |
| * that <code>a.getValue(Action.NAME) == b.ActionName</code> then an |
| * entry is added to the Keymap mapping <code>b</code> to |
| * <code>a</code>. |
| * |
| * @param map The Keymap to add new mappings to |
| * @param bindings The set of bindings to add to the Keymap |
| * @param actions The set of actions to resolve binding names against |
| * |
| * @see Action#NAME |
| * @see Action#getValue |
| * @see KeyBinding#actionName |
| */ |
| 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)); |
| } |
| |
| /** |
| * Returns the set of available Actions this component's associated |
| * editor can run. Equivalent to calling |
| * <code>getUI().getEditorKit().getActions()</code>. This set of Actions |
| * is a reasonable value to provide as a parameter to {@link |
| * #loadKeymap}, when resolving a set of {@link KeyBinding} objects |
| * against this component. |
| * |
| * @return The set of available Actions on this component's {@link EditorKit} |
| * |
| * @see TextUI#getEditorKit |
| * @see EditorKit#getActions() |
| */ |
| public Action[] getActions() |
| { |
| return getUI().getEditorKit(this).getActions(); |
| } |
| |
| // These are package-private to avoid an accessor method. |
| Document doc; |
| Caret caret; |
| boolean editable; |
| |
| private Highlighter highlighter; |
| private Color caretColor; |
| private Color disabledTextColor; |
| private Color selectedTextColor; |
| private Color selectionColor; |
| private Insets margin; |
| private boolean dragEnabled; |
| |
| /** |
| * Creates a new <code>JTextComponent</code> instance. |
| */ |
| public JTextComponent() |
| { |
| Keymap defkeymap = getKeymap(DEFAULT_KEYMAP); |
| if (defkeymap == null) |
| { |
| defkeymap = addKeymap(DEFAULT_KEYMAP, null); |
| defkeymap.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction()); |
| } |
| |
| setFocusable(true); |
| setEditable(true); |
| enableEvents(AWTEvent.KEY_EVENT_MASK); |
| setOpaque(true); |
| updateUI(); |
| } |
| |
| public void setDocument(Document newDoc) |
| { |
| Document oldDoc = doc; |
| try |
| { |
| if (oldDoc instanceof AbstractDocument) |
| ((AbstractDocument) oldDoc).readLock(); |
| |
| doc = newDoc; |
| firePropertyChange("document", oldDoc, newDoc); |
| } |
| finally |
| { |
| if (oldDoc instanceof AbstractDocument) |
| ((AbstractDocument) oldDoc).readUnlock(); |
| } |
| revalidate(); |
| repaint(); |
| } |
| |
| public Document getDocument() |
| { |
| return doc; |
| } |
| |
| /** |
| * Get the <code>AccessibleContext</code> of this object. |
| * |
| * @return an <code>AccessibleContext</code> object |
| */ |
| public AccessibleContext getAccessibleContext() |
| { |
| return new AccessibleJTextComponent(); |
| } |
| |
| public void setMargin(Insets m) |
| { |
| margin = m; |
| } |
| |
| public Insets getMargin() |
| { |
| return margin; |
| } |
| |
| public void setText(String text) |
| { |
| try |
| { |
| if (doc instanceof AbstractDocument) |
| ((AbstractDocument) doc).replace(0, doc.getLength(), text, null); |
| else |
| { |
| doc.remove(0, doc.getLength()); |
| doc.insertString(0, text, null); |
| } |
| } |
| catch (BadLocationException e) |
| { |
| // This can never happen. |
| throw (InternalError) new InternalError().initCause(e); |
| } |
| } |
| |
| /** |
| * Retrieves the current text in this text document. |
| * |
| * @return the text |
| * |
| * @exception NullPointerException if the underlaying document is null |
| */ |
| public String getText() |
| { |
| if (doc == null) |
| return null; |
| |
| try |
| { |
| return doc.getText(0, doc.getLength()); |
| } |
| catch (BadLocationException e) |
| { |
| // This should never happen. |
| return ""; |
| } |
| } |
| |
| /** |
| * Retrieves a part of the current text in this document. |
| * |
| * @param offset the postion of the first character |
| * @param length the length of the text to retrieve |
| * |
| * @return the text |
| * |
| * @exception BadLocationException if arguments do not hold pre-conditions |
| */ |
| public String getText(int offset, int length) |
| throws BadLocationException |
| { |
| return getDocument().getText(offset, length); |
| } |
| |
| /** |
| * Retrieves the currently selected text in this text document. |
| * |
| * @return the selected text |
| * |
| * @exception NullPointerException if the underlaying document is null |
| */ |
| public String getSelectedText() |
| { |
| int start = getSelectionStart(); |
| int offset = getSelectionEnd() - start; |
| |
| if (offset <= 0) |
| return null; |
| |
| try |
| { |
| return doc.getText(start, offset); |
| } |
| catch (BadLocationException e) |
| { |
| // This should never happen. |
| return null; |
| } |
| } |
| |
| /** |
| * Returns a string that specifies the name of the Look and Feel class |
| * that renders this component. |
| * |
| * @return the string "TextComponentUI" |
| */ |
| public String getUIClassID() |
| { |
| return "TextComponentUI"; |
| } |
| |
| /** |
| * Returns a string representation of this JTextComponent. |
| */ |
| protected String paramString() |
| { |
| // TODO: Do something useful here. |
| return super.paramString(); |
| } |
| |
| /** |
| * This method returns the label's UI delegate. |
| * |
| * @return The label's UI delegate. |
| */ |
| public TextUI getUI() |
| { |
| return (TextUI) ui; |
| } |
| |
| /** |
| * This method sets the label's UI delegate. |
| * |
| * @param newUI The label's UI delegate. |
| */ |
| public void setUI(TextUI newUI) |
| { |
| super.setUI(newUI); |
| } |
| |
| /** |
| * This method resets the label's UI delegate to the default UI for the |
| * current look and feel. |
| */ |
| public void updateUI() |
| { |
| setUI((TextUI) UIManager.getUI(this)); |
| } |
| |
| public Dimension getPreferredScrollableViewportSize() |
| { |
| return getPreferredSize(); |
| } |
| |
| public int getScrollableUnitIncrement(Rectangle visible, int orientation, |
| int direction) |
| { |
| // We return 1/10 of the visible area as documented in Sun's API docs. |
| if (orientation == SwingConstants.HORIZONTAL) |
| return visible.width / 10; |
| else if (orientation == SwingConstants.VERTICAL) |
| return visible.height / 10; |
| else |
| throw new IllegalArgumentException("orientation must be either " |
| + "javax.swing.SwingConstants.VERTICAL " |
| + "or " |
| + "javax.swing.SwingConstants.HORIZONTAL" |
| ); |
| } |
| |
| public int getScrollableBlockIncrement(Rectangle visible, int orientation, |
| int direction) |
| { |
| // We return the whole visible area as documented in Sun's API docs. |
| if (orientation == SwingConstants.HORIZONTAL) |
| return visible.width; |
| else if (orientation == SwingConstants.VERTICAL) |
| return visible.height; |
| else |
| throw new IllegalArgumentException("orientation must be either " |
| + "javax.swing.SwingConstants.VERTICAL " |
| + "or " |
| + "javax.swing.SwingConstants.HORIZONTAL" |
| ); |
| } |
| |
| /** |
| * Checks whether this text component it editable. |
| * |
| * @return true if editable, false otherwise |
| */ |
| public boolean isEditable() |
| { |
| return editable; |
| } |
| |
| /** |
| * Enables/disabled this text component's editability. |
| * |
| * @param newValue true to make it editable, false otherwise. |
| */ |
| public void setEditable(boolean newValue) |
| { |
| if (editable == newValue) |
| return; |
| |
| boolean oldValue = editable; |
| editable = newValue; |
| firePropertyChange("editable", oldValue, newValue); |
| } |
| |
| /** |
| * The <code>Caret</code> object used in this text component. |
| * |
| * @return the caret object |
| */ |
| public Caret getCaret() |
| { |
| return caret; |
| } |
| |
| /** |
| * Sets a new <code>Caret</code> for this text component. |
| * |
| * @param newCaret the new <code>Caret</code> to set |
| */ |
| 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); |
| } |
| |
| /** |
| * Retrisves the current caret position. |
| * |
| * @return the current position |
| */ |
| public int getCaretPosition() |
| { |
| return caret.getDot(); |
| } |
| |
| /** |
| * Sets the caret to a new position. |
| * |
| * @param position the new position |
| */ |
| public void setCaretPosition(int position) |
| { |
| if (doc == null) |
| return; |
| |
| if (position < 0 || position > doc.getLength()) |
| throw new IllegalArgumentException(); |
| |
| caret.setDot(position); |
| } |
| |
| /** |
| * Moves the caret to a given position. This selects the text between |
| * the old and the new position of the caret. |
| */ |
| 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); |
| } |
| |
| /** |
| * Returns the start postion of the currently selected text. |
| * |
| * @return the start postion |
| */ |
| public int getSelectionStart() |
| { |
| return Math.min(caret.getDot(), caret.getMark()); |
| } |
| |
| /** |
| * Selects the text from the given postion to the selection end position. |
| * |
| * @param start the start positon of the selected text. |
| */ |
| public void setSelectionStart(int start) |
| { |
| select(start, getSelectionEnd()); |
| } |
| |
| /** |
| * Returns the end postion of the currently selected text. |
| * |
| * @return the end postion |
| */ |
| public int getSelectionEnd() |
| { |
| return Math.max(caret.getDot(), caret.getMark()); |
| } |
| |
| /** |
| * Selects the text from the selection start postion to the given position. |
| * |
| * @param end the end positon of the selected text. |
| */ |
| public void setSelectionEnd(int end) |
| { |
| select(getSelectionStart(), end); |
| } |
| |
| /** |
| * Selects a part of the content of the text component. |
| * |
| * @param start the start position of the selected text |
| * @param end the end position of the selected text |
| */ |
| 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, start); |
| end = Math.min(end, length); |
| |
| setCaretPosition(start); |
| moveCaretPosition(end); |
| } |
| |
| /** |
| * Selects the whole content of the text component. |
| */ |
| public void selectAll() |
| { |
| select(0, doc.getLength()); |
| } |
| |
| public synchronized void replaceSelection(String content) |
| { |
| int dot = caret.getDot(); |
| int mark = caret.getMark(); |
| |
| // If content is empty delete selection. |
| if (content == null) |
| { |
| caret.setDot(dot); |
| return; |
| } |
| |
| try |
| { |
| int start = getSelectionStart(); |
| int end = getSelectionEnd(); |
| |
| // Remove selected text. |
| if (dot != mark) |
| doc.remove(start, end - start); |
| |
| // Insert new text. |
| doc.insertString(start, content, null); |
| |
| // Set dot to new position, |
| dot = start + content.length(); |
| setCaretPosition(dot); |
| |
| // and update it's magic position. |
| caret.setMagicCaretPosition(modelToView(dot).getLocation()); |
| } |
| catch (BadLocationException e) |
| { |
| // This should never happen. |
| } |
| } |
| |
| public boolean getScrollableTracksViewportHeight() |
| { |
| if (getParent() instanceof JViewport) |
| return getParent().getHeight() > getPreferredSize().height; |
| |
| return false; |
| } |
| |
| public boolean getScrollableTracksViewportWidth() |
| { |
| boolean res = false;; |
| Container c = getParent(); |
| if (c instanceof JViewport) |
| res = ((JViewport) c).getExtentSize().width > getPreferredSize().width; |
| |
| return res; |
| } |
| |
| /** |
| * Adds a <code>CaretListener</code> object to this text component. |
| * |
| * @param listener the listener to add |
| */ |
| public void addCaretListener(CaretListener listener) |
| { |
| listenerList.add(CaretListener.class, listener); |
| } |
| |
| /** |
| * Removed a <code>CaretListener</code> object from this text component. |
| * |
| * @param listener the listener to remove |
| */ |
| public void removeCaretListener(CaretListener listener) |
| { |
| listenerList.remove(CaretListener.class, listener); |
| } |
| |
| /** |
| * Returns all added <code>CaretListener</code> objects. |
| * |
| * @return an array of listeners |
| */ |
| public CaretListener[] getCaretListeners() |
| { |
| return (CaretListener[]) getListeners(CaretListener.class); |
| } |
| |
| /** |
| * Notifies all registered <code>CaretListener</code> objects that the caret |
| * was updated. |
| * |
| * @param event the event to send |
| */ |
| protected void fireCaretUpdate(CaretEvent event) |
| { |
| CaretListener[] listeners = getCaretListeners(); |
| |
| for (int index = 0; index < listeners.length; ++index) |
| listeners[index].caretUpdate(event); |
| } |
| |
| /** |
| * Adds an <code>InputListener</code> object to this text component. |
| * |
| * @param listener the listener to add |
| */ |
| public void addInputMethodListener(InputMethodListener listener) |
| { |
| listenerList.add(InputMethodListener.class, listener); |
| } |
| |
| /** |
| * Removes an <code>InputListener</code> object from this text component. |
| * |
| * @param listener the listener to remove |
| */ |
| public void removeInputMethodListener(InputMethodListener listener) |
| { |
| listenerList.remove(InputMethodListener.class, listener); |
| } |
| |
| /** |
| * Returns all added <code>InputMethodListener</code> objects. |
| * |
| * @return an array of listeners |
| */ |
| 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() |
| { |
| if (isEnabled()) |
| doTransferAction("copy", TransferHandler.getCopyAction()); |
| } |
| |
| public void cut() |
| { |
| if (editable && isEnabled()) |
| doTransferAction("cut", TransferHandler.getCutAction()); |
| } |
| |
| public void paste() |
| { |
| if (editable && isEnabled()) |
| doTransferAction("paste", TransferHandler.getPasteAction()); |
| } |
| |
| private void doTransferAction(String name, Action action) |
| { |
| // Install default TransferHandler if none set. |
| if (getTransferHandler() == null) |
| { |
| if (defaultTransferHandler == null) |
| defaultTransferHandler = new DefaultTransferHandler(); |
| |
| setTransferHandler(defaultTransferHandler); |
| } |
| |
| // Perform action. |
| 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; |
| } |
| |
| /** |
| * @since 1.4 |
| */ |
| public NavigationFilter getNavigationFilter() |
| { |
| return navigationFilter; |
| } |
| |
| /** |
| * @since 1.4 |
| */ |
| public void setNavigationFilter(NavigationFilter filter) |
| { |
| navigationFilter = filter; |
| } |
| |
| /** |
| * Read and set the content this component. If not overridden, the |
| * method reads the component content as a plain text. |
| * |
| * The second parameter of this method describes the input stream. It can |
| * be String, URL, File and so on. If not null, this object is added to |
| * the properties of the associated document under the key |
| * {@link Document#StreamDescriptionProperty}. |
| * |
| * @param input an input stream to read from. |
| * @param streamDescription an object, describing the stream. |
| * |
| * @throws IOException if the reader throws it. |
| * |
| * @see #getDocument() |
| * @see Document#getProperty(Object) |
| */ |
| public void read(Reader input, Object streamDescription) |
| throws IOException |
| { |
| if (streamDescription != null) |
| { |
| Document d = getDocument(); |
| if (d != null) |
| d.putProperty(Document.StreamDescriptionProperty, streamDescription); |
| } |
| |
| StringBuffer b = new StringBuffer(); |
| int c; |
| |
| // Read till -1 (EOF). |
| while ((c = input.read()) >= 0) |
| b.append((char) c); |
| |
| setText(b.toString()); |
| } |
| |
| /** |
| * Write the content of this component to the given stream. If not |
| * overridden, the method writes the component content as a plain text. |
| * |
| * @param output the writer to write into. |
| * |
| * @throws IOException if the writer throws it. |
| */ |
| public void write(Writer output) |
| throws IOException |
| { |
| output.write(getText()); |
| } |
| |
| /** |
| * Returns the tooltip text for this text component for the given mouse |
| * event. This forwards the call to |
| * {@link TextUI#getToolTipText(JTextComponent, Point)}. |
| * |
| * @param ev the mouse event |
| * |
| * @return the tooltip text for this text component for the given mouse |
| * event |
| */ |
| public String getToolTipText(MouseEvent ev) |
| { |
| return getUI().getToolTipText(this, ev.getPoint()); |
| } |
| } |