< prev index next >

src/share/classes/javax/swing/JEditorPane.java

Print this page
rev 1527 : 6727662: Code improvement and warnings removing from swing packages
Summary: Removed unnecessary castings and other warnings
Reviewed-by: malenkov
rev 1528 : 6882559: new JEditorPane("text/plain","") fails for null context class loader
Reviewed-by: serb, aivanov
rev 1529 : 8158734: JEditorPane.createEditorKitForContentType throws NPE after 6882559
Reviewed-by: serb, aivanov


 300     }
 301 
 302     /**
 303      * Removes a hyperlink listener.
 304      *
 305      * @param listener the listener
 306      */
 307     public synchronized void removeHyperlinkListener(HyperlinkListener listener) {
 308         listenerList.remove(HyperlinkListener.class, listener);
 309     }
 310 
 311     /**
 312      * Returns an array of all the <code>HyperLinkListener</code>s added
 313      * to this JEditorPane with addHyperlinkListener().
 314      *
 315      * @return all of the <code>HyperLinkListener</code>s added or an empty
 316      *         array if no listeners have been added
 317      * @since 1.4
 318      */
 319     public synchronized HyperlinkListener[] getHyperlinkListeners() {
 320         return (HyperlinkListener[])listenerList.getListeners(
 321                 HyperlinkListener.class);
 322     }
 323 
 324     /**
 325      * Notifies all listeners that have registered interest for
 326      * notification on this event type.  This is normally called
 327      * by the currently installed <code>EditorKit</code> if a content type
 328      * that supports hyperlinks is currently active and there
 329      * was activity with a link.  The listener list is processed
 330      * last to first.
 331      *
 332      * @param e the event
 333      * @see EventListenerList
 334      */
 335     public void fireHyperlinkUpdate(HyperlinkEvent e) {
 336         // Guaranteed to return a non-null array
 337         Object[] listeners = listenerList.getListenerList();
 338         // Process the listeners last to first, notifying
 339         // those that are interested in this event
 340         for (int i = listeners.length-2; i>=0; i-=2) {
 341             if (listeners[i]==HyperlinkListener.class) {


 479                 // Have to scroll after painted.
 480                 SwingUtilities.invokeLater(new Runnable() {
 481                     public void run() {
 482                         scrollToReference(reference);
 483                     }
 484                 });
 485             }
 486             getDocument().putProperty(Document.StreamDescriptionProperty, page);
 487         }
 488         firePropertyChange("page", loaded, page);
 489     }
 490 
 491     /**
 492      * Create model and initialize document properties from page properties.
 493      */
 494     private Document initializeModel(EditorKit kit, URL page) {
 495         Document doc = kit.createDefaultDocument();
 496         if (pageProperties != null) {
 497             // transfer properties discovered in stream to the
 498             // document property collection.
 499             for (Enumeration e = pageProperties.keys(); e.hasMoreElements() ;) {
 500                 Object key = e.nextElement();
 501                 doc.putProperty(key, pageProperties.get(key));
 502             }
 503             pageProperties.clear();
 504         }
 505         if (doc.getProperty(Document.StreamDescriptionProperty) == null) {
 506             doc.putProperty(Document.StreamDescriptionProperty, page);
 507         }
 508         return doc;
 509     }
 510 
 511     /**
 512      * Return load priority for the document or -1 if priority not supported.
 513      */
 514     private int getAsynchronousLoadPriority(Document doc) {
 515         return (doc instanceof AbstractDocument ?
 516             ((AbstractDocument) doc).getAsynchronousLoadPriority() : -1);
 517     }
 518 
 519     /**
 520      * This method initializes from a stream.  If the kit is


 815             try {
 816                 SwingUtilities.invokeAndWait(new Runnable() {
 817                     public void run() {
 818                         handleConnectionProperties(conn);
 819                     }
 820                 });
 821             } catch (InterruptedException e) {
 822                 throw new RuntimeException(e);
 823             } catch (InvocationTargetException e) {
 824                 throw new RuntimeException(e);
 825             }
 826         }
 827         return conn.getInputStream();
 828     }
 829 
 830     /**
 831      * Handle URL connection properties (most notably, content type).
 832      */
 833     private void handleConnectionProperties(URLConnection conn) {
 834         if (pageProperties == null) {
 835             pageProperties = new Hashtable();
 836         }
 837         String type = conn.getContentType();
 838         if (type != null) {
 839             setContentType(type);
 840             pageProperties.put("content-type", type);
 841         }
 842         pageProperties.put(Document.StreamDescriptionProperty, conn.getURL());
 843         String enc = conn.getContentEncoding();
 844         if (enc != null) {
 845             pageProperties.put("content-encoding", enc);
 846         }
 847     }
 848 
 849     private Object getPostData() {
 850         return getDocument().getProperty(PostDataProperty);
 851     }
 852 
 853     private void handlePostData(HttpURLConnection conn, Object postData)
 854                                                             throws IOException {
 855         conn.setDoOutput(true);


1029             if (type.toLowerCase().startsWith("text/")) {
1030                 setCharsetFromContentTypeParameters(paramList);
1031             }
1032         }
1033         if ((kit == null) || (! type.equals(kit.getContentType()))
1034                 || !isUserSetEditorKit) {
1035             EditorKit k = getEditorKitForContentType(type);
1036             if (k != null && k != kit) {
1037                 setEditorKit(k);
1038                 isUserSetEditorKit = false;
1039             }
1040         }
1041 
1042     }
1043 
1044     /**
1045      * This method gets the charset information specified as part
1046      * of the content type in the http header information.
1047      */
1048     private void setCharsetFromContentTypeParameters(String paramlist) {
1049         String charset = null;
1050         try {
1051             // paramlist is handed to us with a leading ';', strip it.
1052             int semi = paramlist.indexOf(';');
1053             if (semi > -1 && semi < paramlist.length()-1) {
1054                 paramlist = paramlist.substring(semi + 1);
1055             }
1056 
1057             if (paramlist.length() > 0) {
1058                 // parse the paramlist into attr-value pairs & get the
1059                 // charset pair's value
1060                 HeaderParser hdrParser = new HeaderParser(paramlist);
1061                 charset = hdrParser.findValue("charset");
1062                 if (charset != null) {
1063                     putClientProperty("charset", charset);
1064                 }
1065             }
1066         }
1067         catch (IndexOutOfBoundsException e) {
1068             // malformed parameter list, use charset we have
1069         }


1120      * Fetches the editor kit to use for the given type
1121      * of content.  This is called when a type is requested
1122      * that doesn't match the currently installed type.
1123      * If the component doesn't have an <code>EditorKit</code> registered
1124      * for the given type, it will try to create an
1125      * <code>EditorKit</code> from the default <code>EditorKit</code> registry.
1126      * If that fails, a <code>PlainEditorKit</code> is used on the
1127      * assumption that all text documents can be represented
1128      * as plain text.
1129      * <p>
1130      * This method can be reimplemented to use some
1131      * other kind of type registry.  This can
1132      * be reimplemented to use the Java Activation
1133      * Framework, for example.
1134      *
1135      * @param type the non-<code>null</code> content type
1136      * @return the editor kit
1137      */
1138     public EditorKit getEditorKitForContentType(String type) {
1139         if (typeHandlers == null) {
1140             typeHandlers = new Hashtable(3);
1141         }
1142         EditorKit k = (EditorKit) typeHandlers.get(type);
1143         if (k == null) {
1144             k = createEditorKitForContentType(type);
1145             if (k != null) {
1146                 setEditorKitForContentType(type, k);
1147             }
1148         }
1149         if (k == null) {
1150             k = createDefaultEditorKit();
1151         }
1152         return k;
1153     }
1154 
1155     /**
1156      * Directly sets the editor kit to use for the given type.  A
1157      * look-and-feel implementation might use this in conjunction
1158      * with <code>createEditorKitForContentType</code> to install handlers for
1159      * content types with a look-and-feel bias.
1160      *
1161      * @param type the non-<code>null</code> content type
1162      * @param k the editor kit to be set
1163      */
1164     public void setEditorKitForContentType(String type, EditorKit k) {
1165         if (typeHandlers == null) {
1166             typeHandlers = new Hashtable(3);
1167         }
1168         typeHandlers.put(type, k);
1169     }
1170 
1171     /**
1172      * Replaces the currently selected content with new content
1173      * represented by the given string.  If there is no selection
1174      * this amounts to an insert of the given text.  If there
1175      * is no replacement text (i.e. the content string is empty
1176      * or <code>null</code>) this amounts to a removal of the
1177      * current selection.  The replacement text will have the
1178      * attributes currently defined for input.  If the component is not
1179      * editable, beep and return.
1180      * <p>
1181      * This method is thread safe, although most Swing methods
1182      * are not. Please see
1183      * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
1184      * to Use Threads</A> for more information.
1185      *
1186      * @param content  the content to replace the selection with.  This


1221     }
1222 
1223     /**
1224      * Creates a handler for the given type from the default registry
1225      * of editor kits.  The registry is created if necessary.  If the
1226      * registered class has not yet been loaded, an attempt
1227      * is made to dynamically load the prototype of the kit for the
1228      * given type.  If the type was registered with a <code>ClassLoader</code>,
1229      * that <code>ClassLoader</code> will be used to load the prototype.
1230      * If there was no registered <code>ClassLoader</code>,
1231      * <code>Class.forName</code> will be used to load the prototype.
1232      * <p>
1233      * Once a prototype <code>EditorKit</code> instance is successfully
1234      * located, it is cloned and the clone is returned.
1235      *
1236      * @param type the content type
1237      * @return the editor kit, or <code>null</code> if there is nothing
1238      *   registered for the given type
1239      */
1240     public static EditorKit createEditorKitForContentType(String type) {
1241         EditorKit k = null;
1242         Hashtable kitRegistry = getKitRegisty();
1243         k = (EditorKit) kitRegistry.get(type);
1244         if (k == null) {
1245             // try to dynamically load the support
1246             String classname = (String) getKitTypeRegistry().get(type);
1247             ClassLoader loader = (ClassLoader) getKitLoaderRegistry().get(type);
1248             try {
1249                 Class c;
1250                 if (loader != null) {
1251                     c = loader.loadClass(classname);
1252                 } else {
1253                     // Will only happen if developer has invoked
1254                     // registerEditorKitForContentType(type, class, null).
1255                     c = Class.forName(classname, true, Thread.currentThread().
1256                                       getContextClassLoader());
1257                 }
1258                 k = (EditorKit) c.newInstance();
1259                 kitRegistry.put(type, k);
1260             } catch (Throwable e) {
1261                 k = null;
1262             }
1263         }
1264 
1265         // create a copy of the prototype or null if there
1266         // is no prototype.
1267         if (k != null) {


1284      */
1285     public static void registerEditorKitForContentType(String type, String classname) {
1286         registerEditorKitForContentType(type, classname,Thread.currentThread().
1287                                         getContextClassLoader());
1288     }
1289 
1290     /**
1291      * Establishes the default bindings of <code>type</code> to
1292      * <code>classname</code>.
1293      * The class will be dynamically loaded later when actually
1294      * needed using the given <code>ClassLoader</code>,
1295      * and can be safely changed
1296      * before attempted uses to avoid loading unwanted classes.
1297      *
1298      * @param type the non-<code>null</code> content type
1299      * @param classname the class to load later
1300      * @param loader the <code>ClassLoader</code> to use to load the name
1301      */
1302     public static void registerEditorKitForContentType(String type, String classname, ClassLoader loader) {
1303         getKitTypeRegistry().put(type, classname);

1304         getKitLoaderRegistry().put(type, loader);



1305         getKitRegisty().remove(type);
1306     }
1307 
1308     /**
1309      * Returns the currently registered <code>EditorKit</code>
1310      * class name for the type <code>type</code>.
1311      *
1312      * @param type  the non-<code>null</code> content type
1313      *
1314      * @since 1.3
1315      */
1316     public static String getEditorKitClassNameForContentType(String type) {
1317         return (String)getKitTypeRegistry().get(type);
1318     }
1319 
1320     private static Hashtable getKitTypeRegistry() {
1321         loadDefaultKitsIfNecessary();
1322         return (Hashtable)SwingUtilities.appContextGet(kitTypeRegistryKey);
1323     }
1324 
1325     private static Hashtable getKitLoaderRegistry() {
1326         loadDefaultKitsIfNecessary();
1327         return (Hashtable)SwingUtilities.appContextGet(kitLoaderRegistryKey);
1328     }
1329 
1330     private static Hashtable getKitRegisty() {
1331         Hashtable ht = (Hashtable)SwingUtilities.appContextGet(kitRegistryKey);
1332         if (ht == null) {
1333             ht = new Hashtable(3);
1334             SwingUtilities.appContextPut(kitRegistryKey, ht);
1335         }
1336         return ht;
1337     }
1338 
1339     /**
1340      * This is invoked every time the registries are accessed. Loading
1341      * is done this way instead of via a static as the static is only
1342      * called once when running in plugin resulting in the entries only
1343      * appearing in the first applet.
1344      */
1345     private static void loadDefaultKitsIfNecessary() {
1346         if (SwingUtilities.appContextGet(kitTypeRegistryKey) == null) {
1347             synchronized(defaultEditorKitMap) {
1348                 if (defaultEditorKitMap.size() == 0) {
1349                     defaultEditorKitMap.put("text/plain",
1350                                             "javax.swing.JEditorPane$PlainEditorKit");


1566             if (count == 0 && ui != null) {
1567                 ui.installUI(this);
1568             }
1569         }
1570     }
1571 
1572     // --- variables ---------------------------------------
1573 
1574     /**
1575      * Stream currently loading asynchronously (potentially cancelable).
1576      * Access to this variable should be synchronized.
1577      */
1578     PageStream loading;
1579 
1580     /**
1581      * Current content binding of the editor.
1582      */
1583     private EditorKit kit;
1584     private boolean isUserSetEditorKit;
1585 
1586     private Hashtable pageProperties;
1587 
1588     /** Should be kept in sync with javax.swing.text.html.FormView counterpart. */
1589     final static String PostDataProperty = "javax.swing.JEditorPane.postdata";
1590 
1591     /**
1592      * Table of registered type handlers for this editor.
1593      */
1594     private Hashtable typeHandlers;
1595 
1596     /*
1597      * Private AppContext keys for this class's static variables.
1598      */
1599     private static final Object kitRegistryKey = new Object(); // JEditorPane.kitRegistry
1600     private static final Object kitTypeRegistryKey = new Object(); // JEditorPane.kitTypeRegistry
1601     private static final Object kitLoaderRegistryKey = new Object(); // JEditorPane.kitLoaderRegistry
1602 
1603     /**
1604      * @see #getUIClassID
1605      * @see #readObject
1606      */
1607     private static final String uiClassID = "EditorPaneUI";
1608 
1609 
1610     /**
1611      * Key for a client property used to indicate whether
1612      * <a href="http://www.w3.org/TR/CSS21/syndata.html#length-units">
1613      * w3c compliant</a> length units are used for html rendering.
1614      * <p>


1964              * Get the index with the hypertext document at which this
1965              * link begins
1966              *
1967              * @return index of start of link
1968              */
1969             public int getStartIndex() {
1970                 return element.getStartOffset();
1971             }
1972 
1973             /**
1974              * Get the index with the hypertext document at which this
1975              * link ends
1976              *
1977              * @return index of end of link
1978              */
1979             public int getEndIndex() {
1980                 return element.getEndOffset();
1981             }
1982         }
1983 
1984         private class LinkVector extends Vector {
1985             public int baseElementIndex(Element e) {
1986                 HTMLLink l;
1987                 for (int i = 0; i < elementCount; i++) {
1988                     l = (HTMLLink) elementAt(i);
1989                     if (l.element == e) {
1990                         return i;
1991                     }
1992                 }
1993                 return -1;
1994             }
1995         }
1996 
1997         LinkVector hyperlinks;
1998         boolean linksValid = false;
1999 
2000         /**
2001          * Build the private table mapping links to locations in the text
2002          */
2003         private void buildLinkTable() {
2004             hyperlinks.removeAllElements();
2005             Document d = JEditorPane.this.getDocument();
2006             if (d != null) {
2007                 ElementIterator ei = new ElementIterator(d);
2008                 Element e;


2080 
2081             // don't need to verify that it's an HREF element; if
2082             // not, then it won't be in the hyperlinks Vector, and
2083             // so indexOf will return -1 in any case
2084             return hyperlinks.baseElementIndex(e);
2085         }
2086 
2087         /**
2088          * Returns the index into an array of hyperlinks that
2089          * index.  If there is no hyperlink at this index, it returns
2090          * null.
2091          *
2092          * @param linkIndex into the set of hyperlinks for this hypertext doc.
2093          * @return string representation of the hyperlink
2094          */
2095         public AccessibleHyperlink getLink(int linkIndex) {
2096             if (linksValid == false) {
2097                 buildLinkTable();
2098             }
2099             if (linkIndex >= 0 && linkIndex < hyperlinks.size()) {
2100                 return (AccessibleHyperlink) hyperlinks.elementAt(linkIndex);
2101             } else {
2102                 return null;
2103             }
2104         }
2105 
2106         /**
2107          * Returns the contiguous text within the document that
2108          * is associated with this hyperlink.
2109          *
2110          * @param linkIndex into the set of hyperlinks for this hypertext doc.
2111          * @return the contiguous text sharing the link at this index
2112          */
2113         public String getLinkText(int linkIndex) {
2114             if (linksValid == false) {
2115                 buildLinkTable();
2116             }
2117             Element e = (Element) hyperlinks.elementAt(linkIndex);
2118             if (e != null) {
2119                 Document d = JEditorPane.this.getDocument();
2120                 if (d != null) {




 300     }
 301 
 302     /**
 303      * Removes a hyperlink listener.
 304      *
 305      * @param listener the listener
 306      */
 307     public synchronized void removeHyperlinkListener(HyperlinkListener listener) {
 308         listenerList.remove(HyperlinkListener.class, listener);
 309     }
 310 
 311     /**
 312      * Returns an array of all the <code>HyperLinkListener</code>s added
 313      * to this JEditorPane with addHyperlinkListener().
 314      *
 315      * @return all of the <code>HyperLinkListener</code>s added or an empty
 316      *         array if no listeners have been added
 317      * @since 1.4
 318      */
 319     public synchronized HyperlinkListener[] getHyperlinkListeners() {
 320         return listenerList.getListeners(javax.swing.event.HyperlinkListener.class);

 321     }
 322 
 323     /**
 324      * Notifies all listeners that have registered interest for
 325      * notification on this event type.  This is normally called
 326      * by the currently installed <code>EditorKit</code> if a content type
 327      * that supports hyperlinks is currently active and there
 328      * was activity with a link.  The listener list is processed
 329      * last to first.
 330      *
 331      * @param e the event
 332      * @see EventListenerList
 333      */
 334     public void fireHyperlinkUpdate(HyperlinkEvent e) {
 335         // Guaranteed to return a non-null array
 336         Object[] listeners = listenerList.getListenerList();
 337         // Process the listeners last to first, notifying
 338         // those that are interested in this event
 339         for (int i = listeners.length-2; i>=0; i-=2) {
 340             if (listeners[i]==HyperlinkListener.class) {


 478                 // Have to scroll after painted.
 479                 SwingUtilities.invokeLater(new Runnable() {
 480                     public void run() {
 481                         scrollToReference(reference);
 482                     }
 483                 });
 484             }
 485             getDocument().putProperty(Document.StreamDescriptionProperty, page);
 486         }
 487         firePropertyChange("page", loaded, page);
 488     }
 489 
 490     /**
 491      * Create model and initialize document properties from page properties.
 492      */
 493     private Document initializeModel(EditorKit kit, URL page) {
 494         Document doc = kit.createDefaultDocument();
 495         if (pageProperties != null) {
 496             // transfer properties discovered in stream to the
 497             // document property collection.
 498             for (Enumeration<String> e = pageProperties.keys(); e.hasMoreElements() ;) {
 499                 String key = e.nextElement();
 500                 doc.putProperty(key, pageProperties.get(key));
 501             }
 502             pageProperties.clear();
 503         }
 504         if (doc.getProperty(Document.StreamDescriptionProperty) == null) {
 505             doc.putProperty(Document.StreamDescriptionProperty, page);
 506         }
 507         return doc;
 508     }
 509 
 510     /**
 511      * Return load priority for the document or -1 if priority not supported.
 512      */
 513     private int getAsynchronousLoadPriority(Document doc) {
 514         return (doc instanceof AbstractDocument ?
 515             ((AbstractDocument) doc).getAsynchronousLoadPriority() : -1);
 516     }
 517 
 518     /**
 519      * This method initializes from a stream.  If the kit is


 814             try {
 815                 SwingUtilities.invokeAndWait(new Runnable() {
 816                     public void run() {
 817                         handleConnectionProperties(conn);
 818                     }
 819                 });
 820             } catch (InterruptedException e) {
 821                 throw new RuntimeException(e);
 822             } catch (InvocationTargetException e) {
 823                 throw new RuntimeException(e);
 824             }
 825         }
 826         return conn.getInputStream();
 827     }
 828 
 829     /**
 830      * Handle URL connection properties (most notably, content type).
 831      */
 832     private void handleConnectionProperties(URLConnection conn) {
 833         if (pageProperties == null) {
 834             pageProperties = new Hashtable<String, Object>();
 835         }
 836         String type = conn.getContentType();
 837         if (type != null) {
 838             setContentType(type);
 839             pageProperties.put("content-type", type);
 840         }
 841         pageProperties.put(Document.StreamDescriptionProperty, conn.getURL());
 842         String enc = conn.getContentEncoding();
 843         if (enc != null) {
 844             pageProperties.put("content-encoding", enc);
 845         }
 846     }
 847 
 848     private Object getPostData() {
 849         return getDocument().getProperty(PostDataProperty);
 850     }
 851 
 852     private void handlePostData(HttpURLConnection conn, Object postData)
 853                                                             throws IOException {
 854         conn.setDoOutput(true);


1028             if (type.toLowerCase().startsWith("text/")) {
1029                 setCharsetFromContentTypeParameters(paramList);
1030             }
1031         }
1032         if ((kit == null) || (! type.equals(kit.getContentType()))
1033                 || !isUserSetEditorKit) {
1034             EditorKit k = getEditorKitForContentType(type);
1035             if (k != null && k != kit) {
1036                 setEditorKit(k);
1037                 isUserSetEditorKit = false;
1038             }
1039         }
1040 
1041     }
1042 
1043     /**
1044      * This method gets the charset information specified as part
1045      * of the content type in the http header information.
1046      */
1047     private void setCharsetFromContentTypeParameters(String paramlist) {
1048         String charset;
1049         try {
1050             // paramlist is handed to us with a leading ';', strip it.
1051             int semi = paramlist.indexOf(';');
1052             if (semi > -1 && semi < paramlist.length()-1) {
1053                 paramlist = paramlist.substring(semi + 1);
1054             }
1055 
1056             if (paramlist.length() > 0) {
1057                 // parse the paramlist into attr-value pairs & get the
1058                 // charset pair's value
1059                 HeaderParser hdrParser = new HeaderParser(paramlist);
1060                 charset = hdrParser.findValue("charset");
1061                 if (charset != null) {
1062                     putClientProperty("charset", charset);
1063                 }
1064             }
1065         }
1066         catch (IndexOutOfBoundsException e) {
1067             // malformed parameter list, use charset we have
1068         }


1119      * Fetches the editor kit to use for the given type
1120      * of content.  This is called when a type is requested
1121      * that doesn't match the currently installed type.
1122      * If the component doesn't have an <code>EditorKit</code> registered
1123      * for the given type, it will try to create an
1124      * <code>EditorKit</code> from the default <code>EditorKit</code> registry.
1125      * If that fails, a <code>PlainEditorKit</code> is used on the
1126      * assumption that all text documents can be represented
1127      * as plain text.
1128      * <p>
1129      * This method can be reimplemented to use some
1130      * other kind of type registry.  This can
1131      * be reimplemented to use the Java Activation
1132      * Framework, for example.
1133      *
1134      * @param type the non-<code>null</code> content type
1135      * @return the editor kit
1136      */
1137     public EditorKit getEditorKitForContentType(String type) {
1138         if (typeHandlers == null) {
1139             typeHandlers = new Hashtable<String, EditorKit>(3);
1140         }
1141         EditorKit k = typeHandlers.get(type);
1142         if (k == null) {
1143             k = createEditorKitForContentType(type);
1144             if (k != null) {
1145                 setEditorKitForContentType(type, k);
1146             }
1147         }
1148         if (k == null) {
1149             k = createDefaultEditorKit();
1150         }
1151         return k;
1152     }
1153 
1154     /**
1155      * Directly sets the editor kit to use for the given type.  A
1156      * look-and-feel implementation might use this in conjunction
1157      * with <code>createEditorKitForContentType</code> to install handlers for
1158      * content types with a look-and-feel bias.
1159      *
1160      * @param type the non-<code>null</code> content type
1161      * @param k the editor kit to be set
1162      */
1163     public void setEditorKitForContentType(String type, EditorKit k) {
1164         if (typeHandlers == null) {
1165             typeHandlers = new Hashtable<String, EditorKit>(3);
1166         }
1167         typeHandlers.put(type, k);
1168     }
1169 
1170     /**
1171      * Replaces the currently selected content with new content
1172      * represented by the given string.  If there is no selection
1173      * this amounts to an insert of the given text.  If there
1174      * is no replacement text (i.e. the content string is empty
1175      * or <code>null</code>) this amounts to a removal of the
1176      * current selection.  The replacement text will have the
1177      * attributes currently defined for input.  If the component is not
1178      * editable, beep and return.
1179      * <p>
1180      * This method is thread safe, although most Swing methods
1181      * are not. Please see
1182      * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
1183      * to Use Threads</A> for more information.
1184      *
1185      * @param content  the content to replace the selection with.  This


1220     }
1221 
1222     /**
1223      * Creates a handler for the given type from the default registry
1224      * of editor kits.  The registry is created if necessary.  If the
1225      * registered class has not yet been loaded, an attempt
1226      * is made to dynamically load the prototype of the kit for the
1227      * given type.  If the type was registered with a <code>ClassLoader</code>,
1228      * that <code>ClassLoader</code> will be used to load the prototype.
1229      * If there was no registered <code>ClassLoader</code>,
1230      * <code>Class.forName</code> will be used to load the prototype.
1231      * <p>
1232      * Once a prototype <code>EditorKit</code> instance is successfully
1233      * located, it is cloned and the clone is returned.
1234      *
1235      * @param type the content type
1236      * @return the editor kit, or <code>null</code> if there is nothing
1237      *   registered for the given type
1238      */
1239     public static EditorKit createEditorKitForContentType(String type) {
1240         Hashtable<String, EditorKit> kitRegistry = getKitRegisty();
1241         EditorKit k = kitRegistry.get(type);

1242         if (k == null) {
1243             // try to dynamically load the support
1244             String classname = getKitTypeRegistry().get(type);
1245             ClassLoader loader = getKitLoaderRegistry().get(type);
1246             try {
1247                 Class c;
1248                 if (loader != null) {
1249                     c = loader.loadClass(classname);
1250                 } else {
1251                     // Will only happen if developer has invoked
1252                     // registerEditorKitForContentType(type, class, null).
1253                     c = Class.forName(classname, true, Thread.currentThread().
1254                                       getContextClassLoader());
1255                 }
1256                 k = (EditorKit) c.newInstance();
1257                 kitRegistry.put(type, k);
1258             } catch (Throwable e) {
1259                 k = null;
1260             }
1261         }
1262 
1263         // create a copy of the prototype or null if there
1264         // is no prototype.
1265         if (k != null) {


1282      */
1283     public static void registerEditorKitForContentType(String type, String classname) {
1284         registerEditorKitForContentType(type, classname,Thread.currentThread().
1285                                         getContextClassLoader());
1286     }
1287 
1288     /**
1289      * Establishes the default bindings of <code>type</code> to
1290      * <code>classname</code>.
1291      * The class will be dynamically loaded later when actually
1292      * needed using the given <code>ClassLoader</code>,
1293      * and can be safely changed
1294      * before attempted uses to avoid loading unwanted classes.
1295      *
1296      * @param type the non-<code>null</code> content type
1297      * @param classname the class to load later
1298      * @param loader the <code>ClassLoader</code> to use to load the name
1299      */
1300     public static void registerEditorKitForContentType(String type, String classname, ClassLoader loader) {
1301         getKitTypeRegistry().put(type, classname);
1302         if (loader != null) {
1303             getKitLoaderRegistry().put(type, loader);
1304         } else {
1305             getKitLoaderRegistry().remove(type);
1306         }
1307         getKitRegisty().remove(type);
1308     }
1309 
1310     /**
1311      * Returns the currently registered <code>EditorKit</code>
1312      * class name for the type <code>type</code>.
1313      *
1314      * @param type  the non-<code>null</code> content type
1315      *
1316      * @since 1.3
1317      */
1318     public static String getEditorKitClassNameForContentType(String type) {
1319         return getKitTypeRegistry().get(type);
1320     }
1321 
1322     private static Hashtable<String, String> getKitTypeRegistry() {
1323         loadDefaultKitsIfNecessary();
1324         return (Hashtable)SwingUtilities.appContextGet(kitTypeRegistryKey);
1325     }
1326 
1327     private static Hashtable<String, ClassLoader> getKitLoaderRegistry() {
1328         loadDefaultKitsIfNecessary();
1329         return (Hashtable)SwingUtilities.appContextGet(kitLoaderRegistryKey);
1330     }
1331 
1332     private static Hashtable<String, EditorKit> getKitRegisty() {
1333         Hashtable ht = (Hashtable)SwingUtilities.appContextGet(kitRegistryKey);
1334         if (ht == null) {
1335             ht = new Hashtable(3);
1336             SwingUtilities.appContextPut(kitRegistryKey, ht);
1337         }
1338         return ht;
1339     }
1340 
1341     /**
1342      * This is invoked every time the registries are accessed. Loading
1343      * is done this way instead of via a static as the static is only
1344      * called once when running in plugin resulting in the entries only
1345      * appearing in the first applet.
1346      */
1347     private static void loadDefaultKitsIfNecessary() {
1348         if (SwingUtilities.appContextGet(kitTypeRegistryKey) == null) {
1349             synchronized(defaultEditorKitMap) {
1350                 if (defaultEditorKitMap.size() == 0) {
1351                     defaultEditorKitMap.put("text/plain",
1352                                             "javax.swing.JEditorPane$PlainEditorKit");


1568             if (count == 0 && ui != null) {
1569                 ui.installUI(this);
1570             }
1571         }
1572     }
1573 
1574     // --- variables ---------------------------------------
1575 
1576     /**
1577      * Stream currently loading asynchronously (potentially cancelable).
1578      * Access to this variable should be synchronized.
1579      */
1580     PageStream loading;
1581 
1582     /**
1583      * Current content binding of the editor.
1584      */
1585     private EditorKit kit;
1586     private boolean isUserSetEditorKit;
1587 
1588     private Hashtable<String, Object> pageProperties;
1589 
1590     /** Should be kept in sync with javax.swing.text.html.FormView counterpart. */
1591     final static String PostDataProperty = "javax.swing.JEditorPane.postdata";
1592 
1593     /**
1594      * Table of registered type handlers for this editor.
1595      */
1596     private Hashtable<String, EditorKit> typeHandlers;
1597 
1598     /*
1599      * Private AppContext keys for this class's static variables.
1600      */
1601     private static final Object kitRegistryKey = new Object(); // JEditorPane.kitRegistry
1602     private static final Object kitTypeRegistryKey = new Object(); // JEditorPane.kitTypeRegistry
1603     private static final Object kitLoaderRegistryKey = new Object(); // JEditorPane.kitLoaderRegistry
1604 
1605     /**
1606      * @see #getUIClassID
1607      * @see #readObject
1608      */
1609     private static final String uiClassID = "EditorPaneUI";
1610 
1611 
1612     /**
1613      * Key for a client property used to indicate whether
1614      * <a href="http://www.w3.org/TR/CSS21/syndata.html#length-units">
1615      * w3c compliant</a> length units are used for html rendering.
1616      * <p>


1966              * Get the index with the hypertext document at which this
1967              * link begins
1968              *
1969              * @return index of start of link
1970              */
1971             public int getStartIndex() {
1972                 return element.getStartOffset();
1973             }
1974 
1975             /**
1976              * Get the index with the hypertext document at which this
1977              * link ends
1978              *
1979              * @return index of end of link
1980              */
1981             public int getEndIndex() {
1982                 return element.getEndOffset();
1983             }
1984         }
1985 
1986         private class LinkVector extends Vector<HTMLLink> {
1987             public int baseElementIndex(Element e) {
1988                 HTMLLink l;
1989                 for (int i = 0; i < elementCount; i++) {
1990                     l = elementAt(i);
1991                     if (l.element == e) {
1992                         return i;
1993                     }
1994                 }
1995                 return -1;
1996             }
1997         }
1998 
1999         LinkVector hyperlinks;
2000         boolean linksValid = false;
2001 
2002         /**
2003          * Build the private table mapping links to locations in the text
2004          */
2005         private void buildLinkTable() {
2006             hyperlinks.removeAllElements();
2007             Document d = JEditorPane.this.getDocument();
2008             if (d != null) {
2009                 ElementIterator ei = new ElementIterator(d);
2010                 Element e;


2082 
2083             // don't need to verify that it's an HREF element; if
2084             // not, then it won't be in the hyperlinks Vector, and
2085             // so indexOf will return -1 in any case
2086             return hyperlinks.baseElementIndex(e);
2087         }
2088 
2089         /**
2090          * Returns the index into an array of hyperlinks that
2091          * index.  If there is no hyperlink at this index, it returns
2092          * null.
2093          *
2094          * @param linkIndex into the set of hyperlinks for this hypertext doc.
2095          * @return string representation of the hyperlink
2096          */
2097         public AccessibleHyperlink getLink(int linkIndex) {
2098             if (linksValid == false) {
2099                 buildLinkTable();
2100             }
2101             if (linkIndex >= 0 && linkIndex < hyperlinks.size()) {
2102                 return hyperlinks.elementAt(linkIndex);
2103             } else {
2104                 return null;
2105             }
2106         }
2107 
2108         /**
2109          * Returns the contiguous text within the document that
2110          * is associated with this hyperlink.
2111          *
2112          * @param linkIndex into the set of hyperlinks for this hypertext doc.
2113          * @return the contiguous text sharing the link at this index
2114          */
2115         public String getLinkText(int linkIndex) {
2116             if (linksValid == false) {
2117                 buildLinkTable();
2118             }
2119             Element e = (Element) hyperlinks.elementAt(linkIndex);
2120             if (e != null) {
2121                 Document d = JEditorPane.this.getDocument();
2122                 if (d != null) {


< prev index next >