mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			608 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			608 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* JTextArea.java --
 | |
|    Copyright (C) 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;
 | |
| 
 | |
| import java.awt.Dimension;
 | |
| import java.awt.FontMetrics;
 | |
| import java.awt.Rectangle;
 | |
| 
 | |
| import javax.accessibility.AccessibleContext;
 | |
| import javax.accessibility.AccessibleStateSet;
 | |
| import javax.swing.text.BadLocationException;
 | |
| import javax.swing.text.Document;
 | |
| import javax.swing.text.Element;
 | |
| import javax.swing.text.JTextComponent;
 | |
| import javax.swing.text.PlainDocument;
 | |
| import javax.swing.text.View;
 | |
| 
 | |
| /**
 | |
|  * The <code>JTextArea</code> component provides a multi-line area for displaying
 | |
|  * and editing plain text.  The component is designed to act as a lightweight
 | |
|  * replacement for the heavyweight <code>java.awt.TextArea</code> component,
 | |
|  * which provides similar functionality using native widgets.
 | |
|  * <p>
 | |
|  *
 | |
|  * This component has additional functionality to the AWT class.  It follows
 | |
|  * the same design pattern as seen in other text components, such as
 | |
|  * <code>JTextField</code>, <code>JTextPane</code> and <code>JEditorPane</code>,
 | |
|  * and embodied in <code>JTextComponent</code>.  These classes separate the text
 | |
|  * (the model) from its appearance within the onscreen component (the view).  The
 | |
|  * text is held within a <code>javax.swing.text.Document</code> object, which can
 | |
|  * also maintain relevant style information where necessary.  As a result, it is the
 | |
|  * document that should be monitored for textual changes, via
 | |
|  * <code>DocumentEvent</code>s delivered to registered
 | |
|  * <code>DocumentListener</code>s, rather than this component.
 | |
|  * <p>
 | |
|  *
 | |
|  * Unlike <code>java.awt.TextArea</code>, <code>JTextArea</code> does not
 | |
|  * handle scrolling.  Instead, this functionality is delegated to a
 | |
|  * <code>JScrollPane</code>, which can contain the text area and handle
 | |
|  * scrolling when required.  Likewise, the word wrapping functionality
 | |
|  * of the AWT component is converted to a property of this component
 | |
|  * and the <code>rows</code> and <code>columns</code> properties
 | |
|  * are used in calculating the preferred size of the scroll pane's
 | |
|  * view port.
 | |
|  *
 | |
|  * @author Michael Koch  (konqueror@gmx.de)
 | |
|  * @author Andrew John Hughes  (gnu_andrew@member.fsf.org)
 | |
|  * @see java.awt.TextArea
 | |
|  * @see javax.swing.text.JTextComponent
 | |
|  * @see javax.swing.JTextField
 | |
|  * @see javax.swing.JTextPane
 | |
|  * @see javax.swing.JEditorPane
 | |
|  * @see javax.swing.text.Document
 | |
|  * @see javax.swing.event.DocumentEvent
 | |
|  * @see javax.swing.event.DocumentListener
 | |
|  */
 | |
| 
 | |
| public class JTextArea extends JTextComponent
 | |
| {
 | |
|   /**
 | |
|    * Provides accessibility support for <code>JTextArea</code>.
 | |
|    *
 | |
|    * @author Roman Kennke (kennke@aicas.com)
 | |
|    */
 | |
|   protected class AccessibleJTextArea extends AccessibleJTextComponent
 | |
|   {
 | |
| 
 | |
|     /**
 | |
|      * Creates a new <code>AccessibleJTextArea</code> object.
 | |
|      */
 | |
|     protected AccessibleJTextArea()
 | |
|     {
 | |
|       super();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Returns the accessible state of this <code>AccessibleJTextArea</code>.
 | |
|      *
 | |
|      * @return  the accessible state of this <code>AccessibleJTextArea</code>
 | |
|      */
 | |
|     public AccessibleStateSet getAccessibleStateSet()
 | |
|     {
 | |
|       AccessibleStateSet state = super.getAccessibleStateSet();
 | |
|       // TODO: Figure out what state must be added here to the super's state.
 | |
|       return state;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Compatible with Sun's JDK
 | |
|    */
 | |
|   private static final long serialVersionUID = -6141680179310439825L;
 | |
| 
 | |
|   /**
 | |
|    * The number of rows used by the component.
 | |
|    */
 | |
|   private int rows;
 | |
| 
 | |
|   /**
 | |
|    * The number of columns used by the component.
 | |
|    */
 | |
|   private int columns;
 | |
| 
 | |
|   /**
 | |
|    * Whether line wrapping is enabled or not.
 | |
|    */
 | |
|   private boolean lineWrap;
 | |
| 
 | |
|   /**
 | |
|    * The number of characters equal to a tab within the text.
 | |
|    */
 | |
|   private int tabSize = 8;
 | |
| 
 | |
|   private boolean wrapStyleWord;
 | |
| 
 | |
|   /**
 | |
|    * Creates a new <code>JTextArea</code> object.
 | |
|    */
 | |
|   public JTextArea()
 | |
|   {
 | |
|     this(null, null, 0, 0);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new <code>JTextArea</code> object.
 | |
|    *
 | |
|    * @param text the initial text
 | |
|    */
 | |
|   public JTextArea(String text)
 | |
|   {
 | |
|     this(null, text, 0, 0);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new <code>JTextArea</code> object.
 | |
|    *
 | |
|    * @param rows the number of rows
 | |
|    * @param columns the number of cols
 | |
|    *
 | |
|    * @exception IllegalArgumentException if rows or columns are negative
 | |
|    */
 | |
|   public JTextArea(int rows, int columns)
 | |
|   {
 | |
|     this(null, null, rows, columns);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new <code>JTextArea</code> object.
 | |
|    *
 | |
|    * @param text the initial text
 | |
|    * @param rows the number of rows
 | |
|    * @param columns the number of cols
 | |
|    *
 | |
|    * @exception IllegalArgumentException if rows or columns are negative
 | |
|    */
 | |
|   public JTextArea(String text, int rows, int columns)
 | |
|   {
 | |
|     this(null, text, rows, columns);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new <code>JTextArea</code> object.
 | |
|    *
 | |
|    * @param doc the document model to use
 | |
|    */
 | |
|   public JTextArea(Document doc)
 | |
|   {
 | |
|     this(doc, null, 0, 0);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates a new <code>JTextArea</code> object.
 | |
|    *
 | |
|    * @param doc the document model to use
 | |
|    * @param text the initial text
 | |
|    * @param rows the number of rows
 | |
|    * @param columns the number of cols
 | |
|    *
 | |
|    * @exception IllegalArgumentException if rows or columns are negative
 | |
|    */
 | |
|   public JTextArea(Document doc, String text, int rows, int columns)
 | |
|   {
 | |
|     setDocument(doc == null ? createDefaultModel() : doc);
 | |
|     // Only explicitly setText() when there is actual text since
 | |
|     // setText() might be overridden and not expected to be called
 | |
|     // from the constructor (as in JEdit).
 | |
|     if (text != null)
 | |
|       setText(text);
 | |
|     setRows(rows);
 | |
|     setColumns(columns);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Appends the supplied text to the current contents
 | |
|    * of the document model.
 | |
|    *
 | |
|    * @param toAppend the text to append
 | |
|    */
 | |
|   public void append(String toAppend)
 | |
|   {
 | |
|       try
 | |
|           {
 | |
|               getDocument().insertString(getText().length(), toAppend, null);
 | |
|           }
 | |
|       catch (BadLocationException exception)
 | |
|           {
 | |
|               /* This shouldn't happen in theory -- but, if it does...  */
 | |
|               throw new RuntimeException("Unexpected exception occurred.", exception);
 | |
|           }
 | |
|       if (toAppend != null && toAppend.length() > 0)
 | |
|         revalidate();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates the default document model.
 | |
|    *
 | |
|    * @return a new default model
 | |
|    */
 | |
|   protected Document createDefaultModel()
 | |
|   {
 | |
|     return new PlainDocument();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns true if the width of this component should be forced
 | |
|    * to match the width of a surrounding view port.  When line wrapping
 | |
|    * is turned on, this method returns true.
 | |
|    *
 | |
|    * @return true if lines are wrapped.
 | |
|    */
 | |
|   public boolean getScrollableTracksViewportWidth()
 | |
|   {
 | |
|     return lineWrap ? true : super.getScrollableTracksViewportWidth();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the increment that is needed to expose exactly one new line
 | |
|    * of text. This is implemented here to return the values of
 | |
|    * {@link #getRowHeight} and {@link #getColumnWidth}, depending on
 | |
|    * the value of the argument <code>direction</code>.
 | |
|    *
 | |
|    * @param visibleRect the view area that is visible in the viewport
 | |
|    * @param orientation either {@link SwingConstants#VERTICAL} or
 | |
|    *     {@link SwingConstants#HORIZONTAL}
 | |
|    * @param direction less than zero for up/left scrolling, greater
 | |
|    *     than zero for down/right scrolling
 | |
|    *
 | |
|    * @return the increment that is needed to expose exactly one new row
 | |
|    *     or column of text
 | |
|    *
 | |
|    * @throws IllegalArgumentException if <code>orientation</code> is invalid
 | |
|    */
 | |
|   public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
 | |
|                                         int direction)
 | |
|   {
 | |
|     if (orientation == SwingConstants.VERTICAL)
 | |
|       return getRowHeight();
 | |
|     else if (orientation == SwingConstants.HORIZONTAL)
 | |
|       return getColumnWidth();
 | |
|     else
 | |
|       throw new IllegalArgumentException("orientation must be either "
 | |
|                                      + "javax.swing.SwingConstants.VERTICAL "
 | |
|                                      + "or "
 | |
|                                      + "javax.swing.SwingConstants.HORIZONTAL"
 | |
|                                      );
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the preferred size of that text component in the case
 | |
|    * it is embedded within a JScrollPane. This uses the column and
 | |
|    * row settings if they are explicitly set, or fall back to
 | |
|    * the superclass's behaviour.
 | |
|    *
 | |
|    * @return the preferred size of that text component in the case
 | |
|    *     it is embedded within a JScrollPane
 | |
|    */
 | |
|   public Dimension getPreferredScrollableViewportSize()
 | |
|   {
 | |
|     if ((rows > 0) && (columns > 0))
 | |
|       return new Dimension(columns * getColumnWidth(), rows * getRowHeight());
 | |
|     else
 | |
|       return super.getPreferredScrollableViewportSize();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the UI class ID string.
 | |
|    *
 | |
|    * @return the string "TextAreaUI"
 | |
|    */
 | |
|   public String getUIClassID()
 | |
|   {
 | |
|     return "TextAreaUI";
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the current number of columns.
 | |
|    *
 | |
|    * @return number of columns
 | |
|    */
 | |
|   public int getColumns()
 | |
|   {
 | |
|     return columns;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the number of rows.
 | |
|    *
 | |
|    * @param columns number of columns
 | |
|    *
 | |
|    * @exception IllegalArgumentException if columns is negative
 | |
|    */
 | |
|   public void setColumns(int columns)
 | |
|   {
 | |
|     if (columns < 0)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     if (columns != this.columns)
 | |
|       {
 | |
|         this.columns = columns;
 | |
|         revalidate();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the current number of rows.
 | |
|    *
 | |
|    * @return number of rows
 | |
|    */
 | |
|   public int getRows()
 | |
|   {
 | |
|     return rows;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the number of rows.
 | |
|    *
 | |
|    * @param rows number of rows
 | |
|    *
 | |
|    * @exception IllegalArgumentException if rows is negative
 | |
|    */
 | |
|   public void setRows(int rows)
 | |
|   {
 | |
|     if (rows < 0)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     if (rows != this.rows)
 | |
|       {
 | |
|         this.rows = rows;
 | |
|         revalidate();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Checks whether line wrapping is enabled.
 | |
|    *
 | |
|    * @return <code>true</code> if line wrapping is enabled,
 | |
|    * <code>false</code> otherwise
 | |
|    */
 | |
|   public boolean getLineWrap()
 | |
|   {
 | |
|     return lineWrap;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Enables/disables line wrapping.
 | |
|    *
 | |
|    * @param flag <code>true</code> to enable line wrapping,
 | |
|    * <code>false</code> otherwise
 | |
|    */
 | |
|   public void setLineWrap(boolean flag)
 | |
|   {
 | |
|     if (lineWrap == flag)
 | |
|       return;
 | |
| 
 | |
|     boolean oldValue = lineWrap;
 | |
|     lineWrap = flag;
 | |
|     firePropertyChange("lineWrap", oldValue, lineWrap);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Checks whether word style wrapping is enabled.
 | |
|    *
 | |
|    * @return <code>true</code> if word style wrapping is enabled,
 | |
|    * <code>false</code> otherwise
 | |
|    */
 | |
|   public boolean getWrapStyleWord()
 | |
|   {
 | |
|     return wrapStyleWord;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Enables/Disables word style wrapping.
 | |
|    *
 | |
|    * @param flag <code>true</code> to enable word style wrapping,
 | |
|    * <code>false</code> otherwise
 | |
|    */
 | |
|   public void setWrapStyleWord(boolean flag)
 | |
|   {
 | |
|     if (wrapStyleWord == flag)
 | |
|       return;
 | |
| 
 | |
|     boolean oldValue = wrapStyleWord;
 | |
|     wrapStyleWord = flag;
 | |
|     firePropertyChange("wrapStyleWord", oldValue, wrapStyleWord);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the number of characters used for a tab.
 | |
|    * This defaults to 8.
 | |
|    *
 | |
|    * @return the current number of spaces used for a tab.
 | |
|    */
 | |
|   public int getTabSize()
 | |
|   {
 | |
|     return tabSize;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the number of characters used for a tab to the
 | |
|    * supplied value.  If a change to the tab size property
 | |
|    * occurs (i.e. newSize != tabSize), a property change event
 | |
|    * is fired.
 | |
|    *
 | |
|    * @param newSize The new number of characters to use for a tab.
 | |
|    */
 | |
|   public void setTabSize(int newSize)
 | |
|   {
 | |
|     if (tabSize == newSize)
 | |
|       return;
 | |
| 
 | |
|     int oldValue = tabSize;
 | |
|     tabSize = newSize;
 | |
|     firePropertyChange("tabSize", oldValue, tabSize);
 | |
|   }
 | |
| 
 | |
|   protected int getColumnWidth()
 | |
|   {
 | |
|     FontMetrics metrics = getToolkit().getFontMetrics(getFont());
 | |
|     return metrics.charWidth('m');
 | |
|   }
 | |
| 
 | |
|   public int getLineCount()
 | |
|   {
 | |
|     return getDocument().getDefaultRootElement().getElementCount();
 | |
|   }
 | |
| 
 | |
|   public int getLineStartOffset(int line)
 | |
|      throws BadLocationException
 | |
|   {
 | |
|     int lineCount = getLineCount();
 | |
| 
 | |
|     if (line < 0 || line > lineCount)
 | |
|       throw new BadLocationException("Non-existing line number", line);
 | |
| 
 | |
|     Element lineElem = getDocument().getDefaultRootElement().getElement(line);
 | |
|     return lineElem.getStartOffset();
 | |
|   }
 | |
| 
 | |
|   public int getLineEndOffset(int line)
 | |
|      throws BadLocationException
 | |
|   {
 | |
|     int lineCount = getLineCount();
 | |
| 
 | |
|     if (line < 0 || line > lineCount)
 | |
|       throw new BadLocationException("Non-existing line number", line);
 | |
| 
 | |
|     Element lineElem = getDocument().getDefaultRootElement().getElement(line);
 | |
|     return lineElem.getEndOffset();
 | |
|   }
 | |
| 
 | |
|   public int getLineOfOffset(int offset)
 | |
|     throws BadLocationException
 | |
|   {
 | |
|     Document doc = getDocument();
 | |
| 
 | |
|     if (offset < doc.getStartPosition().getOffset()
 | |
|         || offset >= doc.getEndPosition().getOffset())
 | |
|       throw new BadLocationException("offset outside of document", offset);
 | |
| 
 | |
|     return doc.getDefaultRootElement().getElementIndex(offset);
 | |
|   }
 | |
| 
 | |
|   protected int getRowHeight()
 | |
|   {
 | |
|     FontMetrics metrics = getToolkit().getFontMetrics(getFont());
 | |
|     return metrics.getHeight();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Inserts the supplied text at the specified position.  Nothing
 | |
|    * happens in the case that the model or the supplied string is null
 | |
|    * or of zero length.
 | |
|    *
 | |
|    * @param string The string of text to insert.
 | |
|    * @param position The position at which to insert the supplied text.
 | |
|    * @throws IllegalArgumentException if the position is < 0 or greater
 | |
|    * than the length of the current text.
 | |
|    */
 | |
|   public void insert(String string, int position)
 | |
|   {
 | |
|     // Retrieve the document model.
 | |
|     Document doc = getDocument();
 | |
| 
 | |
|     // Check the model and string for validity.
 | |
|     if (doc == null
 | |
|         || string == null
 | |
|         || string.length() == 0)
 | |
|       return;
 | |
| 
 | |
|     // Insert the text into the model.
 | |
|     try
 | |
|       {
 | |
|         doc.insertString(position, string, null);
 | |
|       }
 | |
|     catch (BadLocationException e)
 | |
|       {
 | |
|         throw new IllegalArgumentException("The supplied position, "
 | |
|                                            + position + ", was invalid.");
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void replaceRange(String text, int start, int end)
 | |
|   {
 | |
|     Document doc = getDocument();
 | |
| 
 | |
|     if (start > end
 | |
|         || start < doc.getStartPosition().getOffset()
 | |
|         || end >= doc.getEndPosition().getOffset())
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     try
 | |
|       {
 | |
|         doc.remove(start, end - start);
 | |
|         doc.insertString(start, text, null);
 | |
|       }
 | |
|     catch (BadLocationException e)
 | |
|       {
 | |
|         // This cannot happen as we check offset above.
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the preferred size for the JTextArea. This is the maximum of
 | |
|    * the size that is needed to display the content and the requested size
 | |
|    * as per {@link #getColumns} and {@link #getRows}.
 | |
|    *
 | |
|    * @return the preferred size of the JTextArea
 | |
|    */
 | |
|   public Dimension getPreferredSize()
 | |
|   {
 | |
|     int reqWidth = getColumns() * getColumnWidth();
 | |
|     int reqHeight = getRows() * getRowHeight();
 | |
|     View view = getUI().getRootView(this);
 | |
|     int neededWidth = (int) view.getPreferredSpan(View.HORIZONTAL);
 | |
|     int neededHeight = (int) view.getPreferredSpan(View.VERTICAL);
 | |
|     return new Dimension(Math.max(reqWidth, neededWidth),
 | |
|                           Math.max(reqHeight, neededHeight));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the accessible context associated with the <code>JTextArea</code>.
 | |
|    *
 | |
|    * @return the accessible context associated with the <code>JTextArea</code>
 | |
|    */
 | |
|   public AccessibleContext getAccessibleContext()
 | |
|   {
 | |
|     if (accessibleContext == null)
 | |
|       accessibleContext = new AccessibleJTextArea();
 | |
|     return accessibleContext;
 | |
|   }
 | |
| }
 |