This fixes the JEditorPane editor kit registry/loading code to use the
specified classloader. If none is specified, this falls back to the
calling thread's context classloader.

This also fixes one rather ugly issue. So far we cleared the static
editor kit registry every time when a new JEditorPane was created. This
is of course wrong.

I also added static caching of editor kit instances just like Sun does.

2006-12-07  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/JEditorPane.java
        (EditorKitMapping): New inner helper class.
        (editorKits): New static field for caching editor kit instances.
        (static_initiazer): Initialize static mappings here.
        (createEditorKitForContentType): Try to use cached instance.
        Use correct classloader for loading.
        (getEditorKitClassNameForContentType): Make use of EditorKitMapping
        class.
        (getEditorKitForContentType): Store the fetched editor kit.
        Fallback to createDefaultEditorKit().
        (init): Don't clean the static registry here.
        (registerEditorKitForContentType(String,String,ClassLoader)):
        Implemented.
        (registerEditorKitForContentType(String,String)): Delegate to
        the other version of this method with the thread's context
        classloader.

/Roman

Index: javax/swing/JEditorPane.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JEditorPane.java,v
retrieving revision 1.43
diff -u -1 -5 -r1.43 JEditorPane.java
--- javax/swing/JEditorPane.java	7 Dec 2006 22:07:22 -0000	1.43
+++ javax/swing/JEditorPane.java	8 Dec 2006 13:55:51 -0000
@@ -475,30 +475,58 @@
             }
           catch (BadLocationException ex)
             {
               throw (AssertionError)
                 new AssertionError("BadLocationException must not be thrown "
                                    + "here.")
                   .initCause(ex);
             }
         }
       else
         return null;
     }
   }
 
   /**
+   * Used to store a mapping for content-type to editor kit class.
+   */
+  private static class EditorKitMapping
+  {
+    /**
+     * The classname of the editor kit.
+     */
+    String className;
+
+    /**
+     * The classloader with which the kit is to be loaded.
+     */
+    ClassLoader classLoader;
+
+    /**
+     * Creates a new EditorKitMapping object.
+     * 
+     * @param cn the classname
+     * @param cl the classloader
+     */
+    EditorKitMapping(String cn, ClassLoader cl)
+    {
+      className = cn;
+      classLoader = cl;
+    }
+  }
+
+  /**
    * An EditorKit used for plain text. This is the default editor kit for
    * JEditorPanes.
    *
    * @author Roman Kennke ([EMAIL PROTECTED])
    */
   private static class PlainEditorKit extends DefaultEditorKit
   {
 
     /**
      * Returns a ViewFactory that supplies WrappedPlainViews.
      */
     public ViewFactory getViewFactory()
     {
       return new ViewFactory()
       {
@@ -620,33 +648,53 @@
          }
      }
 
      void cancel()
      {
        in.cancel();
      }
   }
 
   private static final long serialVersionUID = 3140472492599046285L;
   
   private EditorKit editorKit;
   
   boolean focus_root;
   
+  /**
+   * Maps content-types to editor kit instances.
+   */
+  static HashMap editorKits;
+
   // A mapping between content types and registered EditorKit types
   static HashMap registerMap;
-  
+
+  static
+  {
+    registerMap = new HashMap();
+    editorKits = new HashMap();
+    registerEditorKitForContentType("application/rtf",
+                                    "javax.swing.text.rtf.RTFEditorKit");
+    registerEditorKitForContentType("text/plain",
+                                    "javax.swing.JEditorPane$PlainEditorKit");
+    registerEditorKitForContentType("text/html",
+                                    "javax.swing.text.html.HTMLEditorKit");
+    registerEditorKitForContentType("text/rtf",
+                                    "javax.swing.text.rtf.RTFEditorKit");
+
+  }
+
   // A mapping between content types and used EditorKits
   HashMap editorMap;  
 
   /**
    * The currently loading stream, if any.
    */
   private PageLoader loader;
 
   public JEditorPane()
   {
     init();
     setEditorKit(createDefaultEditorKit());
   }
 
   public JEditorPane(String url) throws IOException
@@ -663,75 +711,71 @@
 
   public JEditorPane(URL url) throws IOException
   {
     init();
     setEditorKit(createEditorKitForContentType("text/html"));;
     setPage(url);
   }
   
   /**
    * Called by the constructors to set up the default bindings for content 
    * types and EditorKits.
    */
   void init()
   {
     editorMap = new HashMap();
-    registerMap = new HashMap();
-    registerEditorKitForContentType("application/rtf",
-                                    "javax.swing.text.rtf.RTFEditorKit");
-    registerEditorKitForContentType("text/plain",
-                                    "javax.swing.JEditorPane$PlainEditorKit");
-    registerEditorKitForContentType("text/html",
-                                    "javax.swing.text.html.HTMLEditorKit");
-    registerEditorKitForContentType("text/rtf",
-                                    "javax.swing.text.rtf.RTFEditorKit");
   }
 
   protected EditorKit createDefaultEditorKit()
   {
     return new PlainEditorKit();
   }
 
   /**
    * Creates and returns an EditorKit that is appropriate for the given 
    * content type.  This is created using the default recognized types
    * plus any EditorKit types that have been registered.
    * 
    * @see #registerEditorKitForContentType(String, String)
    * @see #registerEditorKitForContentType(String, String, ClassLoader)
    * @param type the content type
    * @return an EditorKit for use with the given content type
    */
   public static EditorKit createEditorKitForContentType(String type)
   {
-    // TODO: Have to handle the case where a ClassLoader was specified
-    // when the EditorKit was registered
-    EditorKit e = null;
-    String className = (String) registerMap.get(type);
-    if (className != null)
+    // Try cached instance.
+    EditorKit e = (EditorKit) editorKits.get(type);
+    if (e == null)
       {
-        try
-        {
-          // XXX - This should actually depend on the classloader
-          // registered with the type. See registerEditorKitForContentType.
-          ClassLoader ldr = ClassLoader.getSystemClassLoader();
-          e = (EditorKit) Class.forName(className, true, ldr).newInstance();
-        }
-        catch (Exception e2)
-        {    
-          // TODO: Not sure what to do here.
-        }
+        EditorKitMapping m = (EditorKitMapping) registerMap.get(type);
+        if (m != null)
+          {
+            String className = m.className;
+            ClassLoader loader = m.classLoader;
+            try
+              {
+                e = (EditorKit) loader.loadClass(className).newInstance();
+              }
+            catch (Exception e2)
+              {    
+                // The reference implementation returns null when class is not
+                // loadable or instantiatable.
+              }
+          }
+        // Cache this for later retrieval.
+        if (e != null)
+          editorKits.put(type, e);
       }
     return e;
   }
 
   /**
    * Sends a given <code>HyperlinkEvent</code> to all registered listeners.
    *
    * @param event the event to send
    */
   public void fireHyperlinkUpdate(HyperlinkEvent event)
   {
     HyperlinkListener[] listeners = getHyperlinkListeners();
 
     for (int index = 0; index < listeners.length; ++index)
        listeners[index].hyperlinkUpdate(event);
@@ -768,57 +812,63 @@
     if (editorKit == null)
       setEditorKit(createDefaultEditorKit());
     return editorKit;
   }
 
   /**
    * Returns the class name of the EditorKit associated with the given
    * content type.
    * 
    * @since 1.3
    * @param type the content type
    * @return the class name of the EditorKit associated with this content type
    */
   public static String getEditorKitClassNameForContentType(String type)
   {
-    return (String) registerMap.get(type);
+    EditorKitMapping m = (EditorKitMapping) registerMap.get(type);
+    String kitName = m != null ? m.className : null;
+    return kitName;
   }
 
   /**
    * Returns the EditorKit to use for the given content type.  If an
    * EditorKit has been explicitly set via 
    * <code>setEditorKitForContentType</code>
    * then it will be returned.  Otherwise an attempt will be made to create
    * an EditorKit from the default recognzied content types or any
    * EditorKits that have been registered.  If none can be created, a
    * PlainEditorKit is created.
    * 
    * @see #registerEditorKitForContentType(String, String)
    * @see #registerEditorKitForContentType(String, String, ClassLoader)
    * @param type the content type
    * @return an appropriate EditorKit for the given content type
    */
-  public EditorKit getEditorKitForContentType(String type)
+  public EditorKit 	(String type)
   {
     // First check if an EditorKit has been explicitly set.
     EditorKit e = (EditorKit) editorMap.get(type);
     // Then check to see if we can create one.
     if (e == null)
-      e = createEditorKitForContentType(type);
+      {
+        e = createEditorKitForContentType(type);
+        if (e != null)
+          setEditorKitForContentType(type, e);
+      }
     // Otherwise default to PlainEditorKit.
     if (e == null)
-      e = new PlainEditorKit();
+      e = createDefaultEditorKit();
     return e;
   }
 
   /**
    * Returns the preferred size for the JEditorPane. This is implemented to
    * return the super's preferred size, unless one of
    * [EMAIL PROTECTED] #getScrollableTracksViewportHeight()} or
    * [EMAIL PROTECTED] #getScrollableTracksViewportWidth()} returns <code>true</code>,
    * in which case the preferred width and/or height is replaced by the UI's
    * minimum size.
    *
    * @return the preferred size for the JEditorPane
    */
   public Dimension getPreferredSize()
   {
@@ -950,41 +1000,42 @@
         super.read(inRead, desc);
       }
   }
 
   /**
    * Establishes a binding between type and classname.  This enables
    * us to create an EditorKit later for the given content type.
    * 
    * @param type the content type
    * @param classname the name of the class that is associated with this 
    * content type
    */
   public static void registerEditorKitForContentType(String type,
                                                      String classname)
   {
-    registerMap.put(type, classname);
+    registerEditorKitForContentType(type, classname,
+                               Thread.currentThread().getContextClassLoader());
   }
 
   /**
    * Establishes the default bindings of type to classname.
    */
   public static void registerEditorKitForContentType(String type,
                                                      String classname,
                                                      ClassLoader loader)
   {
-    // TODO: Implement this properly.
+    registerMap.put(type, new EditorKitMapping(classname, loader));
   }
 
   /**
    * Replaces the currently selected content with new content represented
    * by the given string.
    */
   public void replaceSelection(String content)
   {
     // TODO: Implement this properly.
     super.replaceSelection(content);
   }
 
   /**
    * Scrolls the view to the given reference location (that is, the value
    * returned by the UL.getRef method for the URL being displayed).

Reply via email to