I use the instructions to add my own tag http://java-sl.com/custom_tag_html_kit.html
class MyParserDelegator extends ParserDelegator {
public MyParserDelegator()
I looked at the sources of JDK 7: the DTD
is no more store in an attribute dtd
of javax.swing.text.html.parser.ParserDelegator
but in sun.awt.AppContext
. Coming from a sun package, AppContext should not be accessed by classes out of the JRE himself.
So using the sources of javax.swing.text.html.parser.ParserDelegator
, I wrote MyParserDelegator
that load the DTD himself. After that, the custom tag can be added in DTD easily.
The code below also contains the other classes from http://java-sl.com/custom_tag_html_kit.html to get a working example.
import java.awt.Component;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.ComponentView;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTMLEditorKit.Parser;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.swing.text.html.StyleSheet;
import javax.swing.text.html.parser.DTD;
import javax.swing.text.html.parser.DocumentParser;
import javax.swing.text.html.parser.ParserDelegator;
public class CustomTag {
public static String htmlText = "<html>\n" + "<body>\n" + "<p>\n" + "Text before button\n" + "<button>Text for <button> tag</button>\n"
+ "Text after button\n" + "</p>\n" + "</body>\n" + "</html>";
JEditorPane edit = new JEditorPane();
public CustomTag() {
JFrame frame = new JFrame("Custom tag in HTMLEditorKit");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(edit));
edit.setEditorKit(new MyHTMLEditorKit());
edit.setText(htmlText);
frame.setSize(300, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) throws Exception {
new CustomTag();
}
}
class MyHTMLEditorKit extends HTMLEditorKit {
public MyHTMLEditorKit() {
super();
}
@Override
public Document createDefaultDocument() {
StyleSheet styles = getStyleSheet();
StyleSheet ss = new StyleSheet();
ss.addStyleSheet(styles);
MyHTMLDocument doc = new MyHTMLDocument(ss);
doc.setParser(getParser());
doc.setAsynchronousLoadPriority(4);
doc.setTokenThreshold(100);
return doc;
}
@Override
public ViewFactory getViewFactory() {
return new MyHTMLFactory();
}
Parser defaultParser;
@Override
protected Parser getParser() {
if (defaultParser == null) {
defaultParser = new MyParserDelegator();
}
return defaultParser;
}
class MyHTMLFactory extends HTMLFactory implements ViewFactory {
public MyHTMLFactory() {
super();
}
@Override
public View create(Element element) {
HTML.Tag kind = (HTML.Tag) (element.getAttributes().getAttribute(javax.swing.text.StyleConstants.NameAttribute));
if (kind instanceof HTML.UnknownTag && element.getName().equals("button")) {
return new ComponentView(element) {
@Override
protected Component createComponent() {
JButton button = new JButton("Button : text unknown");
try {
int start = getElement().getStartOffset();
int end = getElement().getEndOffset();
String text = getElement().getDocument().getText(start, end - start);
button.setText(text);
} catch (BadLocationException e) {
e.printStackTrace();
}
return button;
}
};
}
return super.create(element);
}
}
}
class MyHTMLDocument extends HTMLDocument {
public MyHTMLDocument(StyleSheet styles) {
super(styles);
}
@Override
public HTMLEditorKit.ParserCallback getReader(int pos) {
Object desc = getProperty(Document.StreamDescriptionProperty);
if (desc instanceof URL) {
setBase((URL) desc);
}
return new MyHTMLReader(pos);
}
class MyHTMLReader extends HTMLDocument.HTMLReader {
public MyHTMLReader(int offset) {
super(offset);
}
@Override
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
if (t.toString().equals("button")) {
registerTag(t, new BlockAction());
}
super.handleStartTag(t, a, pos);
}
}
}
class MyParserDelegator extends Parser {
private DTD _dtd;
public MyParserDelegator() {
String nm = "html32";
try {
_dtd = DTD.getDTD(nm);
createDTD(_dtd, nm);
javax.swing.text.html.parser.Element div = _dtd.getElement("div");
_dtd.defineElement("button", div.getType(), true, true, div.getContent(), null, null, div.getAttributes());
} catch (IOException e) {
// (PENDING) UGLY!
System.out.println("Throw an exception: could not get default dtd: " + nm);
}
}
protected static DTD createDTD(DTD dtd, String name) {
InputStream in = null;
try {
String path = name + ".bdtd";
in = ParserDelegator.class.getResourceAsStream(path);
if (in != null) {
dtd.read(new DataInputStream(new BufferedInputStream(in)));
DTD.putDTDHash(name, dtd);
}
} catch (Exception e) {
System.out.println(e);
}
return dtd;
}
@Override
public void parse(Reader r, ParserCallback cb, boolean ignoreCharSet) throws IOException {
new DocumentParser(_dtd).parse(r, cb, ignoreCharSet);
}
}
It works for me using the following (jdk 1.7):
Field f = javax.swing.text.html.parser.ParserDelegator.class.getDeclaredField("DTD_KEY");
The only change is the key: "DTD_KEY"
upper case!!
I found the key "DTD_KEY" using
Field[] flds = javax.swing.text.html.parser.ParserDelegator.class.getDeclaredFields();
for (Field f: flds)
{
System.err.println(f.getName());
}