I'm trying to load a published Google Doc into a JEditorPane
.
Here's the document: link.
Here's how a JEditorPane renders it:
My observations from the image:
- The HTML is being fetched properly.
JEditorPane
supports at least some CSS (note the shaded bar at top).JEditorPane
gets really confused at the second<style type="text/css">
block in the HTML source. Is it because the<style>
is inside a<div>
and not the<head>
?- There are odd artifacts (U+00C2, decimal 194; Latin capital letter A with circumflex) at certain spaces in the code, which are actually vanilla
U+0020
spaces. Could this be something to do with the byte order? (I've verified that the characters are actually fetched this way byprintln
ing each line.)
I've read this StackOverflow post on the subject and implemented it, but it's not fixing the problem.
I've also noticed that the CSS support is sparse overall (e.g., rendering http://www.stackoverflow.com
produces an undesirable result with lots of blue boxes) but no actual HTML code or artifacts are exposed.
Using a JTextPane
instead of a JEditorPane
produces identical results.
Adding a DTD to the top of the document (tried both XHTML 4.1 Transitional and HTML5's <!DOCTYPE html>
) doesn't work either.
Any thoughts on why this happens and how I can fix it?
For better help sooner, here's my SSCCE:
public class GoogleDocSSCCE extends JPanel {
public static void main(String[] args) {
JFrame frame = new JFrame();
GoogleDocSSCCE gdv = new GoogleDocSSCCE();
gdv.docId = "1jG_rNCfVSD8yhHB9ZgA5YicXK_yDOl9T-fItIgmKa-o";
gdv.refreshDocument();
frame.setContentPane(gdv);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private final JEditorPane docPane;
private String docId;
private static final String PREFIX = "https://docs.google.com/document/d/";
private static final String SUFFIX = "/pub";
public GoogleDocSSCCE() {
super(new BorderLayout());
docPane = new JEditorPane();
docPane.setEditable(false);
docPane.setContentType("text/html");
add(new JScrollPane(docPane), BorderLayout.CENTER);
JButton btnRefresh = new JButton("Refresh Document");
btnRefresh.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
refreshDocument();
}
});
add(btnRefresh, BorderLayout.NORTH);
}
public void refreshDocument() {
if (docId == null || docId.isEmpty()) {
docPane.setText(new String());
return;
}
docPane.setText("<html><body>Loading...</body></html>");
new Thread(new Runnable() {
@Override
public void run() {
boolean success = false;
try {
URL u = new URL(PREFIX + docId + SUFFIX);
InputStream stream = u.openStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(stream));
StringBuilder sbDocument = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sbDocument.append(line);
sbDocument.append('\n');
}
docPane.setText(sbDocument.toString());
success = true;
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(GoogleDocSSCCE.this,
"The given URL is malformed.",
"Error Reading Google Document",
JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
} catch (IOException e) {
JOptionPane.showMessageDialog(GoogleDocSSCCE.this,
"Unable to read the document.",
"Error Reading Google Document",
JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
} finally {
if (!success) {
// We failed.
docPane.setText(new String());
}
}
}
}).start();
}
}