mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			2060 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			2060 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* 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.java.lang.CPStringBuilder;
 | |
| 
 | |
| 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.Shape;
 | |
| 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.text.BreakIterator;
 | |
| 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.AccessibleState;
 | |
| 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.
 | |
|      */
 | |
|     private int caretDot;
 | |
| 
 | |
|     /**
 | |
|      * Construct an AccessibleJTextComponent.
 | |
|      */
 | |
|     public AccessibleJTextComponent()
 | |
|     {
 | |
|       super();
 | |
|       JTextComponent.this.addCaretListener(this);
 | |
|       caretDot = getCaretPosition();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Retrieve the current caret position.  The index of the first
 | |
|      * caret position is 0.
 | |
|      *
 | |
|      * @return caret position
 | |
|      */
 | |
|     public int getCaretPosition()
 | |
|     {
 | |
|       return JTextComponent.this.getCaretPosition();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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 JTextComponent.this.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
 | |
|           || (JTextComponent.this.getText().equals("")))
 | |
|         return 0;
 | |
|       return JTextComponent.this.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()
 | |
|     {
 | |
|       return JTextComponent.this.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)
 | |
|     {
 | |
|       int dot = e.getDot();
 | |
|       int mark = e.getMark();
 | |
|       if (caretDot != dot)
 | |
|         {
 | |
|           firePropertyChange(ACCESSIBLE_CARET_PROPERTY, new Integer(caretDot),
 | |
|                              new Integer(dot));
 | |
|           caretDot = dot;
 | |
|         }
 | |
|       if (mark != dot)
 | |
|         {
 | |
|           firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null,
 | |
|                              getSelectedText());
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Retreive the accessible state set of this component.
 | |
|      *
 | |
|      * @return the accessible state set of this component
 | |
|      */
 | |
|     public AccessibleStateSet getAccessibleStateSet()
 | |
|     {
 | |
|       AccessibleStateSet state = super.getAccessibleStateSet();
 | |
|       if (isEditable())
 | |
|         state.add(AccessibleState.EDITABLE);
 | |
|       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)
 | |
|     {
 | |
|       firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
 | |
|                          new Integer(e.getOffset()));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
 | |
|                          new Integer(e.getOffset()));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null,
 | |
|                          new Integer(e.getOffset()));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       return viewToModel(p);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       // This is basically the same as BasicTextUI.modelToView().
 | |
| 
 | |
|       Rectangle bounds = null;
 | |
|       if (index >= 0 && index < doc.getLength() - 1)
 | |
|         {
 | |
|           if (doc instanceof AbstractDocument)
 | |
|             ((AbstractDocument) doc).readLock();
 | |
|           try
 | |
|             {
 | |
|               TextUI ui = getUI();
 | |
|               if (ui != null)
 | |
|                 {
 | |
|                   // Get editor rectangle.
 | |
|                   Rectangle rect = new Rectangle();
 | |
|                   Insets insets = getInsets();
 | |
|                   rect.x = insets.left;
 | |
|                   rect.y = insets.top;
 | |
|                   rect.width = getWidth() - insets.left - insets.right;
 | |
|                   rect.height = getHeight() - insets.top - insets.bottom;
 | |
|                   View rootView = ui.getRootView(JTextComponent.this);
 | |
|                   if (rootView != null)
 | |
|                     {
 | |
|                       rootView.setSize(rect.width, rect.height);
 | |
|                       Shape s = rootView.modelToView(index,
 | |
|                                                      Position.Bias.Forward,
 | |
|                                                      index + 1,
 | |
|                                                      Position.Bias.Backward,
 | |
|                                                      rect);
 | |
|                       if (s != null)
 | |
|                         bounds = s.getBounds();
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|           catch (BadLocationException ex)
 | |
|             {
 | |
|               // Ignore (return null).
 | |
|             }
 | |
|           finally
 | |
|             {
 | |
|               if (doc instanceof AbstractDocument)
 | |
|                 ((AbstractDocument) doc).readUnlock();
 | |
|             }
 | |
|         }
 | |
|       return bounds;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Return the length of the text in this text component.
 | |
|      *
 | |
|      * @return a character length
 | |
|      */
 | |
|     public int getCharCount()
 | |
|     {
 | |
|       return JTextComponent.this.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)
 | |
|     {
 | |
|       AttributeSet atts;
 | |
|       if (doc instanceof AbstractDocument)
 | |
|         ((AbstractDocument) doc).readLock();
 | |
|       try
 | |
|         {
 | |
|           Element el = doc.getDefaultRootElement();
 | |
|           while (! el.isLeaf())
 | |
|             {
 | |
|               int i = el.getElementIndex(index);
 | |
|               el = el.getElement(i);
 | |
|             }
 | |
|           atts = el.getAttributes();
 | |
|         }
 | |
|       finally
 | |
|         {
 | |
|           if (doc instanceof AbstractDocument)
 | |
|             ((AbstractDocument) doc).readUnlock();
 | |
|         }
 | |
|       return atts;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       return getAtIndexImpl(part, index, 0);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       return getAtIndexImpl(part, index, 1);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       return getAtIndexImpl(part, index, -1);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Implements getAtIndex(), getBeforeIndex() and getAfterIndex().
 | |
|      *
 | |
|      * @param part the part to return, either CHARACTER, WORD or SENTENCE
 | |
|      * @param index the index
 | |
|      * @param dir the direction, -1 for backwards, 0 for here, +1 for forwards
 | |
|      *
 | |
|      * @return the resulting string
 | |
|      */
 | |
|     private String getAtIndexImpl(int part, int index, int dir)
 | |
|     {
 | |
|       String ret = null;
 | |
|       if (doc instanceof AbstractDocument)
 | |
|         ((AbstractDocument) doc).readLock();
 | |
|       try
 | |
|         {
 | |
|           BreakIterator iter = null;
 | |
|           switch (part)
 | |
|           {
 | |
|             case CHARACTER:
 | |
|               iter = BreakIterator.getCharacterInstance(getLocale());
 | |
|               break;
 | |
|             case WORD:
 | |
|               iter = BreakIterator.getWordInstance(getLocale());
 | |
|               break;
 | |
|             case SENTENCE:
 | |
|               iter = BreakIterator.getSentenceInstance(getLocale());
 | |
|               break;
 | |
|             default:
 | |
|               break;
 | |
|           }
 | |
|           String text = doc.getText(0, doc.getLength() - 1);
 | |
|           iter.setText(text);
 | |
|           int start = index;
 | |
|           int end = index;
 | |
|           switch (dir)
 | |
|           {
 | |
|           case 0:
 | |
|             if (iter.isBoundary(index))
 | |
|               {
 | |
|                 start = index;
 | |
|                 end = iter.following(index);
 | |
|               }
 | |
|             else
 | |
|               {
 | |
|                 start = iter.preceding(index);
 | |
|                 end = iter.next();
 | |
|               }
 | |
|             break;
 | |
|           case 1:
 | |
|             start = iter.following(index);
 | |
|             end = iter.next();
 | |
|             break;
 | |
|           case -1:
 | |
|             end = iter.preceding(index);
 | |
|             start = iter.previous();
 | |
|             break;
 | |
|           default:
 | |
|             assert false;
 | |
|           }
 | |
|           ret = text.substring(start, end);
 | |
|         }
 | |
|       catch (BadLocationException ex)
 | |
|         {
 | |
|           // Ignore (return null).
 | |
|         }
 | |
|       finally
 | |
|         {
 | |
|           if (doc instanceof AbstractDocument)
 | |
|             ((AbstractDocument) doc).readUnlock();
 | |
|         }
 | |
|       return ret;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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()
 | |
|     {
 | |
|       return getActions().length;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       String desc = null;
 | |
|       Action[] actions = getActions();
 | |
|       if (i >= 0 && i < actions.length)
 | |
|         desc = (String) actions[i].getValue(Action.NAME);
 | |
|       return desc;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       boolean ret = false;
 | |
|       Action[] actions = getActions();
 | |
|       if (i >= 0 && i < actions.length)
 | |
|         {
 | |
|           ActionEvent ev = new ActionEvent(JTextComponent.this,
 | |
|                                            ActionEvent.ACTION_PERFORMED, null);
 | |
|           actions[i].actionPerformed(ev);
 | |
|           ret = true;
 | |
|         }
 | |
|       return ret;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets the text contents.
 | |
|      *
 | |
|      * @param s - the new text contents.
 | |
|      */
 | |
|     public void setTextContents(String s)
 | |
|     {
 | |
|       setText(s);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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)
 | |
|     {
 | |
|       try
 | |
|         {
 | |
|           doc.insertString(index, s, null);
 | |
|         }
 | |
|       catch (BadLocationException ex)
 | |
|         {
 | |
|           // What should we do with this?
 | |
|           ex.printStackTrace();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 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 JTextComponent.this.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)
 | |
|     {
 | |
|       JTextComponent.this.select(start, end);
 | |
|       JTextComponent.this.cut();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Pastes the text from the system clipboard to the given index.
 | |
|      *
 | |
|      * @param start - the starting index
 | |
|      */
 | |
|     public void paste(int start)
 | |
|     {
 | |
|       JTextComponent.this.setCaretPosition(start);
 | |
|       JTextComponent.this.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)
 | |
|     {
 | |
|       JTextComponent.this.select(start, end);
 | |
|       JTextComponent.this.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)
 | |
|     {
 | |
|       JTextComponent.this.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)
 | |
|     {
 | |
|       if (doc instanceof StyledDocument)
 | |
|         {
 | |
|           StyledDocument sdoc = (StyledDocument) doc;
 | |
|           sdoc.setCharacterAttributes(start, end - start, s, true);
 | |
|         }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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);
 | |
|       }
 | |
| 
 | |
|     CPStringBuilder b = new CPStringBuilder();
 | |
|     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());
 | |
|   }
 | |
| }
 |