-
Notifications
You must be signed in to change notification settings - Fork 549
/
BrowsePanel.java
178 lines (153 loc) · 6.22 KB
/
BrowsePanel.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Copyright (c) 2008 Patrick Wright
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xhtmlrenderer.event.DefaultDocumentListener;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.resource.XMLResource;
import org.xhtmlrenderer.simple.FSScrollPane;
import org.xhtmlrenderer.simple.XHTMLPanel;
import org.xhtmlrenderer.swing.DelegatingUserAgent;
import org.xhtmlrenderer.swing.ImageResourceLoader;
import org.xhtmlrenderer.swing.SwingReplacedElementFactory;
import org.xhtmlrenderer.util.GeneralUtil;
import javax.annotation.Nonnull;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
/**
* This example shows the most basic use of Flying Saucer, to
* display a single page, scrollable, within a JFrame. The input
* is a file name.
*
* @author Patrick Wright
*/
public class BrowsePanel {
private static final Logger log = LoggerFactory.getLogger(BrowsePanel.class);
private String uri;
private XHTMLPanel panel;
private JFrame frame;
private UserAgentCallback uac;
public static void main(String[] args) {
try {
new BrowsePanel().run(args);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
}
}
private void run(String[] args) {
loadAndCheckArgs(args);
EventQueue.invokeLater(() -> {
// Create a JPanel subclass to render the page
panel = new XHTMLPanel();
setupDocumentListener(panel);
setupUserAgentCallback(panel);
// Put our panel in a scrolling pane. You can use
// a regular JScrollPane here, or our FSScrollPane.
// FSScrollPane is already set up to move the correct
// amount when scrolling 1 line or 1 page
FSScrollPane scroll = new FSScrollPane(panel);
frame = new JFrame("Flying Saucer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(scroll);
frame.pack();
frame.setSize(1024, 768);
frame.setVisible(true);
launchLoad();
});
}
private void setupUserAgentCallback(XHTMLPanel panel) {
uac = new DelegatingUserAgent();
ImageResourceLoader irl = new ImageResourceLoader();
irl.setRepaintListener(panel);
((DelegatingUserAgent) uac).setImageResourceLoader(irl);
panel.getSharedContext().setUserAgentCallback(uac);
panel.getSharedContext().setReplacedElementFactory(new SwingReplacedElementFactory(panel, irl));
}
private void setupDocumentListener(final XHTMLPanel panel) {
panel.addDocumentListener(new DefaultDocumentListener() {
public void documentStarted() {
panel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
super.documentStarted();
}
public void documentLoaded() {
panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
frame.setTitle(panel.getDocumentTitle());
}
public void onLayoutException(@Nonnull Throwable t) {
panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
panel.setDocument(getErrorDocument("can't layout: " + t.getMessage()).getDocument());
}
public void onRenderException(@Nonnull Throwable t) {
panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
panel.setDocument(getErrorDocument("can't render: " + t.getMessage()).getDocument());
}
});
}
private XMLResource getErrorDocument(String reason) {
XMLResource xr;
String cleanUri = GeneralUtil.escapeHTML(uri);
String notFound = "<html><h1>Document not found</h1><p>Could not load URI <pre>" + cleanUri + "</pre>, because: " + reason + "</p></html>";
xr = XMLResource.load(new StringReader(notFound));
return xr;
}
private void launchLoad() {
new Thread(() -> {
final Document doc;
try {
if (panel != null ) panel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
doc = getUAC().getXMLResource(uri).getDocument();
} catch (Exception e) {
log.error("Failed to load document from {}", uri, e);
return;
} finally {
if (panel != null ) panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
EventQueue.invokeLater(() -> startRender(doc));
}).start();
}
private UserAgentCallback getUAC() {
return uac;
}
private void startRender(final Document document) {
// first, load the document, so we can trap any parse errors
// in loading;
// Set the XHTML document to render. We use the simplest form
// of the API call, which uses a File reference. There
// are a variety of overloads for setDocument().
panel.setDocument(document, uri);
}
private void loadAndCheckArgs(String[] args) {
if (args.length == 0) {
throw new IllegalArgumentException("Enter a file or URI.");
}
String name = args[0];
if (!new File(name).exists()) {
try {
new URL(name);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("File " + name + " does not exist or is not a URI", e);
}
}
this.uri = name;
}
}