changelog
[nikiroo-utils.git] / src / be / nikiroo / fanfix / reader / BasicReader.java
1 package be.nikiroo.fanfix.reader;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7
8 import be.nikiroo.fanfix.Instance;
9 import be.nikiroo.fanfix.bundles.Config;
10 import be.nikiroo.fanfix.bundles.UiConfig;
11 import be.nikiroo.fanfix.data.MetaData;
12 import be.nikiroo.fanfix.data.Story;
13 import be.nikiroo.fanfix.library.BasicLibrary;
14 import be.nikiroo.fanfix.library.LocalLibrary;
15 import be.nikiroo.fanfix.supported.BasicSupport;
16 import be.nikiroo.utils.Progress;
17 import be.nikiroo.utils.serial.SerialUtils;
18
19 /**
20 * The class that handles the different {@link Story} readers you can use.
21 * <p>
22 * All the readers should be accessed via {@link BasicReader#getReader()}.
23 *
24 * @author niki
25 */
26 public abstract class BasicReader implements Reader {
27 private static BasicLibrary defaultLibrary = Instance.getLibrary();
28 private static ReaderType defaultType = ReaderType.GUI;
29
30 private BasicLibrary lib;
31 private MetaData meta;
32 private Story story;
33 private int chapter;
34
35 /**
36 * Take the default reader type configuration from the config file.
37 */
38 static {
39 String typeString = Instance.getConfig().getString(Config.READER_TYPE);
40 if (typeString != null && !typeString.isEmpty()) {
41 try {
42 ReaderType type = ReaderType.valueOf(typeString.toUpperCase());
43 defaultType = type;
44 } catch (IllegalArgumentException e) {
45 // Do nothing
46 }
47 }
48 }
49
50 @Override
51 public synchronized Story getStory(Progress pg) {
52 if (story == null) {
53 story = getLibrary().getStory(meta.getLuid(), pg);
54 }
55
56 return story;
57 }
58
59 @Override
60 public BasicLibrary getLibrary() {
61 if (lib == null) {
62 lib = defaultLibrary;
63 }
64
65 return lib;
66 }
67
68 @Override
69 public void setLibrary(BasicLibrary lib) {
70 this.lib = lib;
71 }
72
73 @Override
74 public synchronized MetaData getMeta() {
75 return meta;
76 }
77
78 @Override
79 public synchronized void setMeta(MetaData meta) throws IOException {
80 setMeta(meta == null ? null : meta.getLuid()); // must check the library
81 }
82
83 @Override
84 public synchronized void setMeta(String luid) throws IOException {
85 story = null;
86 meta = getLibrary().getInfo(luid);
87
88 if (meta == null) {
89 throw new IOException("Cannot retrieve story from library: " + luid);
90 }
91 }
92
93 @Override
94 public synchronized void setMeta(URL source, Progress pg)
95 throws IOException {
96 BasicSupport support = BasicSupport.getSupport(source);
97 if (support == null) {
98 throw new IOException("URL not supported: " + source.toString());
99 }
100
101 story = support.process(pg);
102 if (story == null) {
103 throw new IOException(
104 "Cannot retrieve story from external source: "
105 + source.toString());
106 }
107
108 meta = story.getMeta();
109 }
110
111 @Override
112 public int getChapter() {
113 return chapter;
114 }
115
116 @Override
117 public void setChapter(int chapter) {
118 this.chapter = chapter;
119 }
120
121 /**
122 * Return a new {@link BasicReader} ready for use if one is configured.
123 * <p>
124 * Can return NULL if none are configured.
125 *
126 * @return a {@link BasicReader}, or NULL if none configured
127 */
128 public static Reader getReader() {
129 try {
130 if (defaultType != null) {
131 return (Reader) SerialUtils.createObject(defaultType
132 .getTypeName());
133 }
134 } catch (Exception e) {
135 Instance.getTraceHandler().error(
136 new Exception("Cannot create a reader of type: "
137 + defaultType + " (Not compiled in?)", e));
138 }
139
140 return null;
141 }
142
143 /**
144 * The default {@link Reader.ReaderType} used when calling
145 * {@link BasicReader#getReader()}.
146 *
147 * @return the default type
148 */
149 public static ReaderType getDefaultReaderType() {
150 return defaultType;
151 }
152
153 /**
154 * The default {@link Reader.ReaderType} used when calling
155 * {@link BasicReader#getReader()}.
156 *
157 * @param defaultType
158 * the new default type
159 */
160 public static void setDefaultReaderType(ReaderType defaultType) {
161 BasicReader.defaultType = defaultType;
162 }
163
164 /**
165 * Change the default {@link LocalLibrary} to open with the
166 * {@link BasicReader}s.
167 *
168 * @param lib
169 * the new {@link LocalLibrary}
170 */
171 public static void setDefaultLibrary(BasicLibrary lib) {
172 BasicReader.defaultLibrary = lib;
173 }
174
175 /**
176 * Return an {@link URL} from this {@link String}, be it a file path or an
177 * actual {@link URL}.
178 *
179 * @param sourceString
180 * the source
181 *
182 * @return the corresponding {@link URL}
183 *
184 * @throws MalformedURLException
185 * if this is neither a file nor a conventional {@link URL}
186 */
187 public static URL getUrl(String sourceString) throws MalformedURLException {
188 if (sourceString == null || sourceString.isEmpty()) {
189 throw new MalformedURLException("Empty url");
190 }
191
192 URL source = null;
193 try {
194 source = new URL(sourceString);
195 } catch (MalformedURLException e) {
196 File sourceFile = new File(sourceString);
197 source = sourceFile.toURI().toURL();
198 }
199
200 return source;
201 }
202
203 /**
204 * Open the {@link Story} with an external reader (the program will be
205 * passed the main file associated with this {@link Story}).
206 *
207 * @param lib
208 * the {@link BasicLibrary} to select the {@link Story} from
209 * @param luid
210 * the {@link Story} LUID
211 *
212 * @throws IOException
213 * in case of I/O error
214 */
215 @Override
216 public void openExternal(BasicLibrary lib, String luid) throws IOException {
217 MetaData meta = lib.getInfo(luid);
218 File target = lib.getFile(luid, null);
219
220 openExternal(meta, target);
221 }
222
223 /**
224 * Open the {@link Story} with an external reader (the program will be
225 * passed the given target file).
226 *
227 * @param meta
228 * the {@link Story} to load
229 * @param target
230 * the target {@link File}
231 *
232 * @throws IOException
233 * in case of I/O error
234 */
235 protected void openExternal(MetaData meta, File target) throws IOException {
236 String program = null;
237 if (meta.isImageDocument()) {
238 program = Instance.getUiConfig().getString(
239 UiConfig.IMAGES_DOCUMENT_READER);
240 } else {
241 program = Instance.getUiConfig().getString(
242 UiConfig.NON_IMAGES_DOCUMENT_READER);
243 }
244
245 if (program != null && program.trim().isEmpty()) {
246 program = null;
247 }
248
249 start(target, program);
250 }
251
252 /**
253 * Start a file and open it with the given program if given or the first
254 * default system starter we can find.
255 *
256 * @param target
257 * the target to open
258 * @param program
259 * the program to use or NULL for the default system starter
260 *
261 * @throws IOException
262 * in case of I/O error
263 */
264 protected void start(File target, String program) throws IOException {
265 if (program == null) {
266 boolean ok = false;
267 for (String starter : new String[] { "xdg-open", "open", "see",
268 "start", "run" }) {
269 try {
270 Runtime.getRuntime().exec(
271 new String[] { starter, target.getAbsolutePath() });
272 ok = true;
273 break;
274 } catch (IOException e) {
275 }
276 }
277 if (!ok) {
278 throw new IOException("Cannot find a program to start the file");
279 }
280 } else {
281 Runtime.getRuntime().exec(
282 new String[] { program, target.getAbsolutePath() });
283 }
284 }
285 }