Perf improvement: covers
[fanfix.git] / src / be / nikiroo / fanfix / reader / LocalReader.java
1 package be.nikiroo.fanfix.reader;
2
3 import java.awt.Desktop;
4 import java.awt.EventQueue;
5 import java.io.File;
6 import java.io.IOException;
7 import java.net.URISyntaxException;
8
9 import javax.swing.JEditorPane;
10 import javax.swing.JLabel;
11 import javax.swing.JOptionPane;
12 import javax.swing.event.HyperlinkEvent;
13 import javax.swing.event.HyperlinkListener;
14
15 import be.nikiroo.fanfix.Instance;
16 import be.nikiroo.fanfix.Library;
17 import be.nikiroo.fanfix.VersionCheck;
18 import be.nikiroo.fanfix.bundles.UiConfig;
19 import be.nikiroo.fanfix.data.MetaData;
20 import be.nikiroo.fanfix.data.Story;
21 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
22 import be.nikiroo.utils.Progress;
23 import be.nikiroo.utils.Version;
24
25 class LocalReader extends BasicReader {
26 private Library lib;
27
28 public LocalReader() throws IOException {
29 File dir = Instance.getReaderDir();
30 dir.mkdirs();
31 if (!dir.exists()) {
32 throw new IOException(
33 "Cannote create cache directory for local reader: " + dir);
34 }
35
36 OutputType text = null;
37 OutputType images = null;
38
39 try {
40 text = OutputType.valueOfNullOkUC(Instance.getUiConfig().getString(
41 UiConfig.NON_IMAGES_DOCUMENT_TYPE));
42 if (text == null) {
43 text = OutputType.HTML;
44 }
45
46 images = OutputType.valueOfNullOkUC(Instance.getUiConfig()
47 .getString(UiConfig.IMAGES_DOCUMENT_TYPE));
48 if (images == null) {
49 images = OutputType.CBZ;
50 }
51 } catch (Exception e) {
52 UiConfig key = (text == null) ? UiConfig.NON_IMAGES_DOCUMENT_TYPE
53 : UiConfig.IMAGES_DOCUMENT_TYPE;
54 String value = Instance.getUiConfig().getString(key);
55
56 throw new IOException(
57 String.format(
58 "The configuration option %s is not valid: %s",
59 key, value), e);
60 }
61
62 lib = new Library(dir, text, images);
63 }
64
65 @Override
66 public void read() throws IOException {
67 if (getStory() == null) {
68 throw new IOException("No story to read");
69 }
70
71 open(getStory().getMeta().getLuid(), null);
72 }
73
74 @Override
75 public void read(int chapter) throws IOException {
76 // TODO: show a special page?
77 read();
78 }
79
80 /**
81 * Import the story into the local reader library, and keep the same LUID.
82 *
83 * @param luid
84 * the Library UID
85 * @param pg
86 * the optional progress reporter
87 *
88 * @throws IOException
89 * in case of I/O error
90 */
91 public void imprt(String luid, Progress pg) throws IOException {
92 Progress pgGetStory = new Progress();
93 Progress pgSave = new Progress();
94 if (pg != null) {
95 pg.setMax(2);
96 pg.addProgress(pgGetStory, 1);
97 pg.addProgress(pgSave, 1);
98 }
99
100 try {
101 Story story = Instance.getLibrary().getStory(luid, pgGetStory);
102 if (story != null) {
103 story = lib.save(story, luid, pgSave);
104 } else {
105 throw new IOException("Cannot find story in Library: " + luid);
106 }
107 } catch (IOException e) {
108 throw new IOException(
109 "Cannot import story from library to LocalReader library: "
110 + luid, e);
111 }
112 }
113
114 /**
115 * Get the target file related to this {@link Story}.
116 *
117 * @param luid
118 * the LUID of the {@link Story}
119 * @param pg
120 * the optional progress reporter
121 *
122 * @return the target file
123 *
124 * @throws IOException
125 * in case of I/O error
126 */
127 public File getTarget(String luid, Progress pg) throws IOException {
128 File file = lib.getFile(luid);
129 if (file == null) {
130 imprt(luid, pg);
131 file = lib.getFile(luid);
132 }
133
134 return file;
135 }
136
137 /**
138 * Check if the {@link Story} denoted by this Library UID is present in the
139 * {@link LocalReader} cache.
140 *
141 * @param luid
142 * the Library UID
143 *
144 * @return TRUE if it is
145 */
146 public boolean isCached(String luid) {
147 return lib.getInfo(luid) != null;
148 }
149
150 @Override
151 public void start(String type) {
152 // TODO: improve presentation of update message
153 final VersionCheck updates = VersionCheck.check();
154 StringBuilder builder = new StringBuilder();
155
156 final JEditorPane updateMessage = new JEditorPane("text/html", "");
157 if (updates.isNewVersionAvailable()) {
158 builder.append("A new version of the program is available at <span style='color: blue;'>https://github.com/nikiroo/fanfix/releases</span>");
159 builder.append("<br>");
160 builder.append("<br>");
161 for (Version v : updates.getNewer()) {
162 builder.append("\t<b>Version " + v + "</b>");
163 builder.append("<br>");
164 builder.append("<ul>");
165 for (String item : updates.getChanges().get(v)) {
166 builder.append("<li>" + item + "</li>");
167 }
168 builder.append("</ul>");
169 }
170
171 // html content
172 updateMessage.setText("<html><body>" //
173 + builder//
174 + "</body></html>");
175
176 // handle link events
177 updateMessage.addHyperlinkListener(new HyperlinkListener() {
178 public void hyperlinkUpdate(HyperlinkEvent e) {
179 if (e.getEventType().equals(
180 HyperlinkEvent.EventType.ACTIVATED))
181 try {
182 Desktop.getDesktop().browse(e.getURL().toURI());
183 } catch (IOException ee) {
184 Instance.syserr(ee);
185 } catch (URISyntaxException ee) {
186 Instance.syserr(ee);
187 }
188 }
189 });
190 updateMessage.setEditable(false);
191 updateMessage.setBackground(new JLabel().getBackground());
192 }
193
194 final String typeFinal = type;
195 EventQueue.invokeLater(new Runnable() {
196 public void run() {
197 if (updates.isNewVersionAvailable()) {
198 int rep = JOptionPane.showConfirmDialog(null,
199 updateMessage, "Updates available",
200 JOptionPane.OK_CANCEL_OPTION);
201 if (rep == JOptionPane.OK_OPTION) {
202 updates.ok();
203 } else {
204 updates.ignore();
205 }
206 }
207
208 new LocalReaderFrame(LocalReader.this, typeFinal)
209 .setVisible(true);
210 }
211 });
212 }
213
214 // delete from local reader library
215 void clearLocalReaderCache(String luid) {
216 lib.delete(luid);
217 }
218
219 // delete from main library
220 void delete(String luid) {
221 lib.delete(luid);
222 Instance.getLibrary().delete(luid);
223 }
224
225 // open the given book
226 void open(String luid, Progress pg) throws IOException {
227 MetaData meta = Instance.getLibrary().getInfo(luid);
228 File target = getTarget(luid, pg);
229
230 String program = null;
231 if (meta.isImageDocument()) {
232 program = Instance.getUiConfig().getString(
233 UiConfig.IMAGES_DOCUMENT_READER);
234 } else {
235 program = Instance.getUiConfig().getString(
236 UiConfig.NON_IMAGES_DOCUMENT_READER);
237 }
238
239 if (program != null && program.trim().isEmpty()) {
240 program = null;
241 }
242
243 if (program == null) {
244 try {
245 Desktop.getDesktop().browse(target.toURI());
246 } catch (UnsupportedOperationException e) {
247 Runtime.getRuntime().exec(
248 new String[] { "xdg-open", target.getAbsolutePath() });
249
250 }
251 } else {
252 Runtime.getRuntime().exec(
253 new String[] { program, target.getAbsolutePath() });
254
255 }
256 }
257 }