Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package javax.swing;
   26   
   27   import java.awt;
   28   import java.awt.event.ActionEvent;
   29   
   30   import java.io.ObjectOutputStream;
   31   import java.io.ObjectInputStream;
   32   import java.io.IOException;
   33   
   34   import javax.swing.text;
   35   import javax.swing.event;
   36   import javax.swing.plaf;
   37   
   38   /**
   39    * A text component that can be marked up with attributes that are
   40    * represented graphically.
   41    * You can find how-to information and examples of using text panes in
   42    * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/text.html">Using Text Components</a>,
   43    * a section in <em>The Java Tutorial.</em>
   44    *
   45    * <p>
   46    * This component models paragraphs
   47    * that are composed of runs of character level attributes.  Each
   48    * paragraph may have a logical style attached to it which contains
   49    * the default attributes to use if not overridden by attributes set
   50    * on the paragraph or character run.  Components and images may
   51    * be embedded in the flow of text.
   52    * <p>
   53    * <dl>
   54    * <dt><b><font size=+1>Newlines</font></b>
   55    * <dd>
   56    * For a discussion on how newlines are handled, see
   57    * <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
   58    * </dl>
   59    *
   60    * <p>
   61    * <strong>Warning:</strong> Swing is not thread safe. For more
   62    * information see <a
   63    * href="package-summary.html#threading">Swing's Threading
   64    * Policy</a>.
   65    * <p>
   66    * <strong>Warning:</strong>
   67    * Serialized objects of this class will not be compatible with
   68    * future Swing releases. The current serialization support is
   69    * appropriate for short term storage or RMI between applications running
   70    * the same version of Swing.  As of 1.4, support for long term storage
   71    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   72    * has been added to the <code>java.beans</code> package.
   73    * Please see {@link java.beans.XMLEncoder}.
   74    *
   75    * @beaninfo
   76    *   attribute: isContainer true
   77    * description: A text component that can be marked up with attributes that are graphically represented.
   78    *
   79    * @author  Timothy Prinzing
   80    * @see javax.swing.text.StyledEditorKit
   81    */
   82   public class JTextPane extends JEditorPane {
   83   
   84       /**
   85        * Creates a new <code>JTextPane</code>.  A new instance of
   86        * <code>StyledEditorKit</code> is
   87        * created and set, and the document model set to <code>null</code>.
   88        */
   89       public JTextPane() {
   90           super();
   91           EditorKit editorKit = createDefaultEditorKit();
   92           String contentType = editorKit.getContentType();
   93           if (contentType != null
   94               && getEditorKitClassNameForContentType(contentType) ==
   95                    defaultEditorKitMap.get(contentType)) {
   96               setEditorKitForContentType(contentType, editorKit);
   97           }
   98           setEditorKit(editorKit);
   99       }
  100   
  101       /**
  102        * Creates a new <code>JTextPane</code>, with a specified document model.
  103        * A new instance of <code>javax.swing.text.StyledEditorKit</code>
  104        *  is created and set.
  105        *
  106        * @param doc the document model
  107        */
  108       public JTextPane(StyledDocument doc) {
  109           this();
  110           setStyledDocument(doc);
  111       }
  112   
  113       /**
  114        * Returns the class ID for the UI.
  115        *
  116        * @return the string "TextPaneUI"
  117        *
  118        * @see JComponent#getUIClassID
  119        * @see UIDefaults#getUI
  120        */
  121       public String getUIClassID() {
  122           return uiClassID;
  123       }
  124   
  125       /**
  126        * Associates the editor with a text document.  This
  127        * must be a <code>StyledDocument</code>.
  128        *
  129        * @param doc  the document to display/edit
  130        * @exception IllegalArgumentException  if <code>doc</code> can't
  131        *   be narrowed to a <code>StyledDocument</code> which is the
  132        *   required type of model for this text component
  133        */
  134       public void setDocument(Document doc) {
  135           if (doc instanceof StyledDocument) {
  136               super.setDocument(doc);
  137           } else {
  138               throw new IllegalArgumentException("Model must be StyledDocument");
  139           }
  140       }
  141   
  142       /**
  143        * Associates the editor with a text document.
  144        * The currently registered factory is used to build a view for
  145        * the document, which gets displayed by the editor.
  146        *
  147        * @param doc  the document to display/edit
  148        */
  149       public void setStyledDocument(StyledDocument doc) {
  150           super.setDocument(doc);
  151       }
  152   
  153       /**
  154        * Fetches the model associated with the editor.
  155        *
  156        * @return the model
  157        */
  158       public StyledDocument getStyledDocument() {
  159           return (StyledDocument) getDocument();
  160       }
  161   
  162       /**
  163        * Replaces the currently selected content with new content
  164        * represented by the given string.  If there is no selection
  165        * this amounts to an insert of the given text.  If there
  166        * is no replacement text this amounts to a removal of the
  167        * current selection.  The replacement text will have the
  168        * attributes currently defined for input at the point of
  169        * insertion.  If the document is not editable, beep and return.
  170        *
  171        * @param content  the content to replace the selection with
  172        */
  173       @Override
  174       public void replaceSelection(String content) {
  175           replaceSelection(content, true);
  176       }
  177   
  178       private void replaceSelection(String content, boolean checkEditable) {
  179           if (checkEditable && !isEditable()) {
  180               UIManager.getLookAndFeel().provideErrorFeedback(JTextPane.this);
  181               return;
  182           }
  183           Document doc = getStyledDocument();
  184           if (doc != null) {
  185               try {
  186                   Caret caret = getCaret();
  187                   boolean composedTextSaved = saveComposedText(caret.getDot());
  188                   int p0 = Math.min(caret.getDot(), caret.getMark());
  189                   int p1 = Math.max(caret.getDot(), caret.getMark());
  190                   AttributeSet attr = getInputAttributes().copyAttributes();
  191                   if (doc instanceof AbstractDocument) {
  192                       ((AbstractDocument)doc).replace(p0, p1 - p0, content,attr);
  193                   }
  194                   else {
  195                       if (p0 != p1) {
  196                           doc.remove(p0, p1 - p0);
  197                       }
  198                       if (content != null && content.length() > 0) {
  199                           doc.insertString(p0, content, attr);
  200                       }
  201                   }
  202                   if (composedTextSaved) {
  203                       restoreComposedText();
  204                   }
  205               } catch (BadLocationException e) {
  206                   UIManager.getLookAndFeel().provideErrorFeedback(JTextPane.this);
  207               }
  208           }
  209       }
  210   
  211       /**
  212        * Inserts a component into the document as a replacement
  213        * for the currently selected content.  If there is no
  214        * selection the component is effectively inserted at the
  215        * current position of the caret.  This is represented in
  216        * the associated document as an attribute of one character
  217        * of content.
  218        * <p>
  219        * The component given is the actual component used by the
  220        * JTextPane.  Since components cannot be a child of more than
  221        * one container, this method should not be used in situations
  222        * where the model is shared by text components.
  223        * <p>
  224        * The component is placed relative to the text baseline
  225        * according to the value returned by
  226        * <code>Component.getAlignmentY</code>.  For Swing components
  227        * this value can be conveniently set using the method
  228        * <code>JComponent.setAlignmentY</code>.  For example, setting
  229        * a value of <code>0.75</code> will cause 75 percent of the
  230        * component to be above the baseline, and 25 percent of the
  231        * component to be below the baseline.
  232        *
  233        * @param c    the component to insert
  234        */
  235       public void insertComponent(Component c) {
  236           MutableAttributeSet inputAttributes = getInputAttributes();
  237           inputAttributes.removeAttributes(inputAttributes);
  238           StyleConstants.setComponent(inputAttributes, c);
  239           replaceSelection(" ", false);
  240           inputAttributes.removeAttributes(inputAttributes);
  241       }
  242   
  243       /**
  244        * Inserts an icon into the document as a replacement
  245        * for the currently selected content.  If there is no
  246        * selection the icon is effectively inserted at the
  247        * current position of the caret.  This is represented in
  248        * the associated document as an attribute of one character
  249        * of content.
  250        *
  251        * @param g    the icon to insert
  252        * @see Icon
  253        */
  254       public void insertIcon(Icon g) {
  255           MutableAttributeSet inputAttributes = getInputAttributes();
  256           inputAttributes.removeAttributes(inputAttributes);
  257           StyleConstants.setIcon(inputAttributes, g);
  258           replaceSelection(" ", false);
  259           inputAttributes.removeAttributes(inputAttributes);
  260       }
  261   
  262       /**
  263        * Adds a new style into the logical style hierarchy.  Style attributes
  264        * resolve from bottom up so an attribute specified in a child
  265        * will override an attribute specified in the parent.
  266        *
  267        * @param nm   the name of the style (must be unique within the
  268        *   collection of named styles).  The name may be <code>null</code>
  269        *   if the style is unnamed, but the caller is responsible
  270        *   for managing the reference returned as an unnamed style can't
  271        *   be fetched by name.  An unnamed style may be useful for things
  272        *   like character attribute overrides such as found in a style
  273        *   run.
  274        * @param parent the parent style.  This may be <code>null</code>
  275        *   if unspecified
  276        *   attributes need not be resolved in some other style.
  277        * @return the new <code>Style</code>
  278        */
  279       public Style addStyle(String nm, Style parent) {
  280           StyledDocument doc = getStyledDocument();
  281           return doc.addStyle(nm, parent);
  282       }
  283   
  284       /**
  285        * Removes a named non-<code>null</code> style previously added to
  286        * the document.
  287        *
  288        * @param nm  the name of the style to remove
  289        */
  290       public void removeStyle(String nm) {
  291           StyledDocument doc = getStyledDocument();
  292           doc.removeStyle(nm);
  293       }
  294   
  295       /**
  296        * Fetches a named non-<code>null</code> style previously added.
  297        *
  298        * @param nm  the name of the style
  299        * @return the <code>Style</code>
  300        */
  301       public Style getStyle(String nm) {
  302           StyledDocument doc = getStyledDocument();
  303           return doc.getStyle(nm);
  304       }
  305   
  306       /**
  307        * Sets the logical style to use for the paragraph at the
  308        * current caret position.  If attributes aren't explicitly set
  309        * for character and paragraph attributes they will resolve
  310        * through the logical style assigned to the paragraph, which
  311        * in term may resolve through some hierarchy completely
  312        * independent of the element hierarchy in the document.
  313        *
  314        * @param s  the logical style to assign to the paragraph,
  315        *          or <code>null</code> for no style
  316        */
  317       public void setLogicalStyle(Style s) {
  318           StyledDocument doc = getStyledDocument();
  319           doc.setLogicalStyle(getCaretPosition(), s);
  320       }
  321   
  322       /**
  323        * Fetches the logical style assigned to the paragraph represented
  324        * by the current position of the caret, or <code>null</code>.
  325        *
  326        * @return the <code>Style</code>
  327        */
  328       public Style getLogicalStyle() {
  329           StyledDocument doc = getStyledDocument();
  330           return doc.getLogicalStyle(getCaretPosition());
  331       }
  332   
  333       /**
  334        * Fetches the character attributes in effect at the
  335        * current location of the caret, or <code>null</code>.
  336        *
  337        * @return the attributes, or <code>null</code>
  338        */
  339       public AttributeSet getCharacterAttributes() {
  340           StyledDocument doc = getStyledDocument();
  341           Element run = doc.getCharacterElement(getCaretPosition());
  342           if (run != null) {
  343               return run.getAttributes();
  344           }
  345           return null;
  346       }
  347   
  348       /**
  349        * Applies the given attributes to character
  350        * content.  If there is a selection, the attributes
  351        * are applied to the selection range.  If there
  352        * is no selection, the attributes are applied to
  353        * the input attribute set which defines the attributes
  354        * for any new text that gets inserted.
  355        *
  356        * @param attr the attributes
  357        * @param replace if true, then replace the existing attributes first
  358        */
  359       public void setCharacterAttributes(AttributeSet attr, boolean replace) {
  360           int p0 = getSelectionStart();
  361           int p1 = getSelectionEnd();
  362           if (p0 != p1) {
  363               StyledDocument doc = getStyledDocument();
  364               doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
  365           } else {
  366               MutableAttributeSet inputAttributes = getInputAttributes();
  367               if (replace) {
  368                   inputAttributes.removeAttributes(inputAttributes);
  369               }
  370               inputAttributes.addAttributes(attr);
  371           }
  372       }
  373   
  374       /**
  375        * Fetches the current paragraph attributes in effect
  376        * at the location of the caret, or <code>null</code> if none.
  377        *
  378        * @return the attributes
  379        */
  380       public AttributeSet getParagraphAttributes() {
  381           StyledDocument doc = getStyledDocument();
  382           Element paragraph = doc.getParagraphElement(getCaretPosition());
  383           if (paragraph != null) {
  384               return paragraph.getAttributes();
  385           }
  386           return null;
  387       }
  388   
  389       /**
  390        * Applies the given attributes to paragraphs.  If
  391        * there is a selection, the attributes are applied
  392        * to the paragraphs that intersect the selection.
  393        * If there is no selection, the attributes are applied
  394        * to the paragraph at the current caret position.
  395        *
  396        * @param attr the non-<code>null</code> attributes
  397        * @param replace if true, replace the existing attributes first
  398        */
  399       public void setParagraphAttributes(AttributeSet attr, boolean replace) {
  400           int p0 = getSelectionStart();
  401           int p1 = getSelectionEnd();
  402           StyledDocument doc = getStyledDocument();
  403           doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
  404       }
  405   
  406       /**
  407        * Gets the input attributes for the pane.
  408        *
  409        * @return the attributes
  410        */
  411       public MutableAttributeSet getInputAttributes() {
  412           return getStyledEditorKit().getInputAttributes();
  413       }
  414   
  415       /**
  416        * Gets the editor kit.
  417        *
  418        * @return the editor kit
  419        */
  420       protected final StyledEditorKit getStyledEditorKit() {
  421           return (StyledEditorKit) getEditorKit();
  422       }
  423   
  424       /**
  425        * @see #getUIClassID
  426        * @see #readObject
  427        */
  428       private static final String uiClassID = "TextPaneUI";
  429   
  430   
  431       /**
  432        * See <code>readObject</code> and <code>writeObject</code> in
  433        * <code>JComponent</code> for more
  434        * information about serialization in Swing.
  435        *
  436        * @param s the output stream
  437        */
  438       private void writeObject(ObjectOutputStream s) throws IOException {
  439           s.defaultWriteObject();
  440           if (getUIClassID().equals(uiClassID)) {
  441               byte count = JComponent.getWriteObjCounter(this);
  442               JComponent.setWriteObjCounter(this, --count);
  443               if (count == 0 && ui != null) {
  444                   ui.installUI(this);
  445               }
  446           }
  447       }
  448   
  449   
  450       // --- JEditorPane ------------------------------------
  451   
  452       /**
  453        * Creates the <code>EditorKit</code> to use by default.  This
  454        * is implemented to return <code>javax.swing.text.StyledEditorKit</code>.
  455        *
  456        * @return the editor kit
  457        */
  458       protected EditorKit createDefaultEditorKit() {
  459           return new StyledEditorKit();
  460       }
  461   
  462       /**
  463        * Sets the currently installed kit for handling
  464        * content.  This is the bound property that
  465        * establishes the content type of the editor.
  466        *
  467        * @param kit the desired editor behavior
  468        * @exception IllegalArgumentException if kit is not a
  469        *          <code>StyledEditorKit</code>
  470        */
  471       public final void setEditorKit(EditorKit kit) {
  472           if (kit instanceof StyledEditorKit) {
  473               super.setEditorKit(kit);
  474           } else {
  475               throw new IllegalArgumentException("Must be StyledEditorKit");
  476           }
  477       }
  478   
  479       /**
  480        * Returns a string representation of this <code>JTextPane</code>.
  481        * This method
  482        * is intended to be used only for debugging purposes, and the
  483        * content and format of the returned string may vary between
  484        * implementations. The returned string may be empty but may not
  485        * be <code>null</code>.
  486        *
  487        * @return  a string representation of this <code>JTextPane</code>
  488        */
  489       protected String paramString() {
  490           return super.paramString();
  491       }
  492   
  493   }

Home » openjdk-7 » javax » swing » [javadoc | source]