home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / JEditorPane.java < prev    next >
Text File  |  1998-02-26  |  15KB  |  502 lines

  1. /*
  2.  * @(#)JEditorPane.java    1.40 98/02/12
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing;
  21.  
  22. import java.awt.*;
  23. import java.awt.event.*;
  24. import java.net.*;
  25. import java.util.Hashtable;
  26. import java.io.*;
  27.  
  28. import com.sun.java.swing.plaf.*;
  29. import com.sun.java.swing.text.*;
  30. import com.sun.java.swing.event.*;
  31. import com.sun.java.swing.text.html.*;
  32. import com.sun.java.accessibility.*;
  33.  
  34. /**
  35.  * <p>
  36.  * A text pane to edit various kinds of content, such
  37.  * as html and rtf.  This uses implementations of the 
  38.  * EditorKit to accomplish it's behavior.  This component
  39.  * effectively morphs into the proper kind of text editor
  40.  * for the kind of content it is given.
  41.  * <p>
  42.  * The content type that editor is bound to at any given
  43.  * time is determined by the EditorKit currently installed.
  44.  * If the content is set to a new URL, it's type is used
  45.  * to determine the EditorKit that should be used to load
  46.  * the content.
  47.  * <p>
  48.  * Warning: serialized objects of this class will not be compatible with
  49.  * future swing releases.  The current serialization support is appropriate 
  50.  * for short term storage or RMI between Swing1.0 applications.  It will
  51.  * not be possible to load serialized Swing1.0 objects with future releases
  52.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  53.  * baseline for the serialized form of Swing objects.
  54.  *
  55.  * @beaninfo
  56.  *   attribute: isContainer false
  57.  *
  58.  * @author  Timothy Prinzing
  59.  * @version 1.40 02/12/98
  60.  */
  61. public class JEditorPane extends JTextComponent {
  62.  
  63.     /**
  64.      * Constructs a new JEditorPane.
  65.      */
  66.     public JEditorPane() {
  67.     super();
  68.     }
  69.  
  70.     /**
  71.      * Creates a JEditorPane based on a specified URL for input.
  72.      *
  73.      * @param initialPage the URL
  74.      * @exception IOException if the URL cannot be accessed
  75.      */
  76.     public JEditorPane(URL initialPage) throws IOException {
  77.     this();
  78.     setPage(initialPage);
  79.     }
  80.  
  81.     /**
  82.      * Creates a JEditorPane based on a string containing a URL specification.
  83.      *
  84.      * @param url the URL
  85.      * @exception IOException if the URL cannot be accessed
  86.      */
  87.     public JEditorPane(String url) throws IOException {
  88.     this();
  89.         setPage(url);
  90.     }
  91.  
  92.     /**
  93.      * Adds a hyperlink listener for notification of any changes.
  94.      *
  95.      * @param listener the listener
  96.      */
  97.     public synchronized void addHyperlinkListener(HyperlinkListener listener) {
  98.     listenerList.add(HyperlinkListener.class, listener);
  99.     }
  100.  
  101.     /**
  102.      * Removes a hyperlink listener.
  103.      *
  104.      * @param listener the listener
  105.      */
  106.     public synchronized void removeHyperlinkListener(HyperlinkListener listener) {
  107.     listenerList.remove(HyperlinkListener.class, listener);
  108.     }
  109.  
  110.     /**
  111.      * Notifies all listeners that have registered interest for
  112.      * notification on this event type.  This is normally called
  113.      * by the currently installed EditorKit if a content type
  114.      * that supports hyperlinks is currently active and there
  115.      * was activity with a link.
  116.      *
  117.      * @param e the event
  118.      * @see EventListenerList
  119.      */
  120.     public void fireHyperlinkUpdate(HyperlinkEvent e) {
  121.     // Guaranteed to return a non-null array
  122.     Object[] listeners = listenerList.getListenerList();
  123.     // Process the listeners last to first, notifying
  124.     // those that are interested in this event
  125.     for (int i = listeners.length-2; i>=0; i-=2) {
  126.         if (listeners[i]==HyperlinkListener.class) {
  127.         ((HyperlinkListener)listeners[i+1]).hyperlinkUpdate(e);
  128.         }           
  129.     }
  130.     }
  131.  
  132.     /**
  133.      * Sets the current url being displayed.  
  134.      *
  135.      * @param page the URL of the page
  136.      * @exception IOException for an invalid page specification
  137.      */
  138.     public void setPage(URL page) throws IOException {
  139.     if (page == null) {
  140.         throw new IOException("invalid url");
  141.     }
  142.  
  143.     InputStream in = page.openStream();
  144.     URLConnection conn = page.openConnection();
  145.     String type = conn.getContentType();
  146.     setContentType(type);
  147.     if (kit != null) {
  148.         Document doc = kit.createDefaultDocument();
  149.         doc.putProperty(Document.StreamDescriptionProperty, page);
  150.         try {
  151.         kit.read(in, doc, 0);
  152.         setDocument(doc);
  153.         } catch (BadLocationException e) {
  154.         throw new IOException(e.getMessage());
  155.         }
  156.     }
  157.     }
  158.  
  159.     /**
  160.      * Gets the current url being displayed.  If a URL was 
  161.      * not specified in the creation of the document, this
  162.      * will return null, and relative URL's will not be 
  163.      * resolved.
  164.      *
  165.      * @return the URL
  166.      */
  167.     public URL getPage() {
  168.     return (URL) getDocument().getProperty(Document.StreamDescriptionProperty);
  169.     }
  170.  
  171.     /**
  172.      * Sets the current url being displayed.
  173.      *
  174.      * @param url the URL for display
  175.      * @exception IOException for an invalid URL specification
  176.      */
  177.     public void setPage(String url) throws IOException {
  178.     if (url == null) {
  179.         throw new IOException("invalid url");
  180.     }
  181.     URL page = new URL(url);
  182.     setPage(page);
  183.     }
  184.  
  185.     /**
  186.      * Gets the class ID for the UI.
  187.      *
  188.      * @return the ID
  189.      * @see JComponent#getUIClassID
  190.      * @see UIDefaults#getUI
  191.      */
  192.     public String getUIClassID() {
  193.     return "EditorPaneUI";
  194.     }
  195.  
  196.     /**
  197.      * Creates the default editor kit for when
  198.      * the component is first created.
  199.      */
  200.     protected EditorKit createDefaultEditorKit() {
  201.     return new DefaultEditorKit();
  202.     }
  203.  
  204.     /**
  205.      * Fetches the currently installed kit for handling
  206.      * content.  
  207.      *
  208.      * @return the editor kit
  209.      */
  210.     public final EditorKit getEditorKit() {
  211.     if (kit == null) {
  212.         kit = createDefaultEditorKit();
  213.     }
  214.     return kit;
  215.     }
  216.  
  217.     /**
  218.      * Gets the type of content that this editor 
  219.      * handles.
  220.      *
  221.      * @return the content type
  222.      */
  223.     public final String getContentType() {
  224.     return (kit != null) ? kit.getContentType() : null;
  225.     }
  226.  
  227.     /**
  228.      * Sets the type of content that this editor
  229.      * handles.  This calls <code>getEditorKitForContentType</code>
  230.      * and <code>setEditorKit</code> if and editor kit can
  231.      * be successfully located.  This is a convenience method
  232.      * that can be used as an alternative to calling 
  233.      * <code>setEditorKit</code> directly.
  234.      * 
  235.      * @param type the mime type for the content editing
  236.      *   support.
  237.      * @see #getContentType
  238.      * @beaninfo
  239.      *  description: the type of content
  240.      */
  241.     public final void setContentType(String type) {
  242.     if ((kit == null) || (! type.equals(kit.getContentType()))) {
  243.         EditorKit k = getEditorKitForContentType(type);
  244.         if (k != null) {
  245.         setEditorKit(k);
  246.         }
  247.     }
  248.     }
  249.  
  250.     /**
  251.      * Sets the currently installed kit for handling
  252.      * content.  This is the bound property that
  253.      * establishes the content type of the editor.
  254.      * 
  255.      * @param kit the desired editor behavior.
  256.      * @see #getEditorKit
  257.      * @beaninfo
  258.      *  description: the currently installed kit for handling content
  259.      *        bound: true
  260.      *       expert: true
  261.      */
  262.     public void setEditorKit(EditorKit kit) {
  263.     EditorKit old = this.kit;
  264.     if (old != null) {
  265.         old.deinstall(this);
  266.     }
  267.     this.kit = kit;
  268.     if (this.kit != null) {
  269.         this.kit.install(this);
  270.         setDocument(this.kit.createDefaultDocument());
  271.     }
  272.     firePropertyChange("editorKit", old, kit);
  273.     }
  274.  
  275.     /**
  276.      * Fetches the editor kit to use for the given type
  277.      * of content.  This is called when a type is requested
  278.      * that doesn't match the currently installed type.
  279.      * If the component doesn't have an EditorKit registered
  280.      * for the given type, it will try to create an 
  281.      * EditorKit from the default EditorKit registry.
  282.      * If that fails, a DefaultEditorKit is used on the
  283.      * assumption that all text documents can be represented
  284.      * as plain text.
  285.      * <p>
  286.      * This method can be reimplemented to use some
  287.      * other kind of type registry.  This can
  288.      * be reimplemented to use the Java Activation
  289.      * Framework for example.
  290.      *
  291.      * @param type the content type
  292.      * @return the editor kit
  293.      */  
  294.     public EditorKit getEditorKitForContentType(String type) {
  295.     if (typeHandlers == null) {
  296.         typeHandlers = new Hashtable(3);
  297.     }
  298.     EditorKit k = (EditorKit) typeHandlers.get(type);
  299.     if (k == null) {
  300.         k = createEditorKitForContentType(type);
  301.         if (k != null) {
  302.         setEditorKitForContentType(type, k);
  303.         }
  304.     }
  305.     if (k == null) {
  306.         k = new DefaultEditorKit();
  307.     }
  308.     return k;
  309.     }
  310.  
  311.     /**
  312.      * Directly set the editor kit to use for the given type.  A 
  313.      * look-and-feel implementation might use this in conjunction
  314.      * with createEditorKitForContentType to install handlers for
  315.      * content types with a look-and-feel bias.
  316.      */
  317.     public void setEditorKitForContentType(String type, EditorKit k) {
  318.     if (typeHandlers == null) {
  319.         typeHandlers = new Hashtable(3);
  320.     }
  321.     typeHandlers.put(type, k);
  322.     }
  323.  
  324.     /**
  325.      * Create a handler for the given type from the default registry
  326.      * of editor kits.
  327.      */
  328.     public static EditorKit createEditorKitForContentType(String type) {
  329.     EditorKit k = null;
  330.         Hashtable kitRegistry = 
  331.             (Hashtable)SwingUtilities.appContextGet(kitRegistryKey);
  332.     if (kitRegistry == null) {
  333.         // nothing has been loaded yet.
  334.         kitRegistry = new Hashtable();
  335.             SwingUtilities.appContextPut(kitRegistryKey, kitRegistry);
  336.     } else {
  337.         k = (EditorKit) kitRegistry.get(type);
  338.     }
  339.     if (k == null) {
  340.         // try to dynamically load the support 
  341.         String classname = (String) getKitTypeRegistry().get(type);
  342.         try {
  343.         Class c = Class.forName(classname);
  344.         k = (EditorKit) c.newInstance();
  345.         kitRegistry.put(type, k);
  346.         } catch (Throwable e) {
  347.         e.printStackTrace();
  348.         k = null;
  349.         }
  350.     }
  351.  
  352.     // create a copy of the prototype or null if there
  353.     // is no prototype.
  354.     if (k != null) {
  355.         return (EditorKit) k.clone();
  356.     }
  357.     return null;
  358.     }
  359.  
  360.     /**
  361.      * Establishes the default bindings of type to name.  
  362.      * The class will be dynamically loaded later when actually
  363.      * needed, and can be safely changed before attempted uses
  364.      * to avoid loading unwanted classes.
  365.      *
  366.      * @param type the content type
  367.      * @param classname the class to load later
  368.      */
  369.     public static void registerEditorKitForContentType(String type, String classname) {
  370.     getKitTypeRegistry().put(type, classname);
  371.     }
  372.  
  373.     // --- JComponent methods ---------------------------------
  374.  
  375.     /**
  376.      * Turns off tab traversal once focus gained.
  377.      *
  378.      * @return true, to indicate that the focus is being managed
  379.      */
  380.     public boolean isManagingFocus() {
  381.         return true;
  382.     }
  383.  
  384.     // --- Scrollable  ----------------------------------------
  385.  
  386.     /**
  387.      * Returns true if a viewport should always force the width of this 
  388.      * Scrollable to match the width of the viewport.  
  389.      * 
  390.      * @return True if a viewport should force the Scrollables width to match its own.
  391.      */
  392.     public boolean getScrollableTracksViewportWidth() {
  393.     // PENDING(prinz) need to change this so the entire Scrollable
  394.     // interface comes from the installed EditorKit if it defines 
  395.     // Scrollable, because many content types have a kind of scrolling
  396.     // policy (eg html has preformatted areas that define minimum width,
  397.     // and rtf has a defined page size).
  398.     return true;
  399.     }
  400.  
  401.  
  402. /////////////////
  403. // Accessibility support
  404. ////////////////
  405.  
  406.  
  407.     /**
  408.      * Get the AccessibleContext associated with this JEditorPane
  409.      *
  410.      * @return the AccessibleContext of this JEditorPane
  411.      */
  412.     public AccessibleContext getAccessibleContext() {
  413.         if (accessibleContext == null) {
  414.             accessibleContext = new AccessibleJEditorPane();
  415.         }
  416.         return accessibleContext;
  417.     }
  418.  
  419.     /**
  420.      * The class used to obtain the accessible role for this object.
  421.      * <p>
  422.      * Warning: serialized objects of this class will not be compatible with
  423.      * future swing releases.  The current serialization support is appropriate
  424.      * for short term storage or RMI between Swing1.0 applications.  It will
  425.      * not be possible to load serialized Swing1.0 objects with future releases
  426.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  427.      * baseline for the serialized form of Swing objects.
  428.      */
  429.     protected class AccessibleJEditorPane extends AccessibleJTextComponent {
  430.  
  431.     /**
  432.      * Get the accessibleDescription property of this object.  If this
  433.      * property isn't set, return the content type of this JEditorPane
  434.      * instead (e.g. "plain/text", "html/text", etc.
  435.      *
  436.      * @return the localized description of the object; null if
  437.      * this object does not have a description
  438.      *
  439.      * @see #setAccessibleName
  440.      */
  441.     public String getAccessibleDescription() {
  442.         if (accessibleDescription != null) {
  443.         return accessibleDescription;
  444.         } else {
  445.         return JEditorPane.this.getContentType();
  446.         }
  447.     }
  448.  
  449.         /**
  450.          * Gets the state set of this object.
  451.          *
  452.          * @return an instance of AccessibleStateSet describing the states
  453.          * of the object
  454.          * @see AccessibleStateSet
  455.          */
  456.         public AccessibleStateSet getAccessibleStateSet() {
  457.             AccessibleStateSet states = super.getAccessibleStateSet();
  458.             states.add(AccessibleState.MULTI_LINE);
  459.             return states;
  460.         }
  461.     }
  462.  
  463.     private static Hashtable getKitTypeRegistry() {
  464.         Hashtable kitTypeRegistry = 
  465.             (Hashtable)SwingUtilities.appContextGet(kitTypeRegistryKey);
  466.     if (kitTypeRegistry == null) {
  467.         kitTypeRegistry = new Hashtable();
  468.             SwingUtilities.appContextPut(kitTypeRegistryKey, kitTypeRegistry);
  469.     }
  470.         return kitTypeRegistry;
  471.     }
  472.  
  473.     // --- variables ---------------------------------------
  474.  
  475.     /**
  476.      * Current content binding of the editor.
  477.      */
  478.     private EditorKit kit;
  479.  
  480.     /**
  481.      * Table of registered type handlers for this editor.
  482.      */
  483.     private Hashtable typeHandlers;
  484.  
  485.     /*
  486.      * Private AppContext keys for this class's static variables.
  487.      */
  488.     private static final Object kitRegistryKey = 
  489.         new StringBuffer("JEditorPane.kitRegistry");
  490.     private static final Object kitTypeRegistryKey = 
  491.         new StringBuffer("JEditorPane.kitTypeRegistry");
  492.  
  493.     {
  494.     // set the default bindings
  495.     registerEditorKitForContentType("text/plain", "com.sun.java.swing.text.DefaultEditorKit");
  496.     registerEditorKitForContentType("text/html", "com.sun.java.swing.text.html.HTMLEditorKit");
  497.     registerEditorKitForContentType("text/rtf", "com.sun.java.swing.text.rtf.RTFEditorKit");
  498.     registerEditorKitForContentType("application/rtf", "com.sun.java.swing.text.rtf.RTFEditorKit");
  499.     }
  500.  
  501. }
  502.