Commit | Line | Data |
---|---|---|
16a81ef7 | 1 | package be.nikiroo.fanfix.reader.ui; |
a6395bef | 2 | |
d3c84ac3 | 3 | import java.awt.BorderLayout; |
4d205683 | 4 | import java.awt.Frame; |
a6395bef NR |
5 | import java.awt.event.ActionEvent; |
6 | import java.awt.event.ActionListener; | |
333f0e7b NR |
7 | import java.awt.event.KeyEvent; |
8 | import java.awt.event.WindowEvent; | |
9 | import java.io.File; | |
a6395bef | 10 | import java.io.IOException; |
4d205683 | 11 | import java.util.HashMap; |
a6395bef | 12 | import java.util.List; |
4d205683 NR |
13 | import java.util.Map; |
14 | import java.util.Map.Entry; | |
a6395bef | 15 | |
10d558d2 | 16 | import javax.swing.JFileChooser; |
a6395bef | 17 | import javax.swing.JFrame; |
333f0e7b NR |
18 | import javax.swing.JMenu; |
19 | import javax.swing.JMenuBar; | |
20 | import javax.swing.JMenuItem; | |
21 | import javax.swing.JOptionPane; | |
9843a5e5 | 22 | import javax.swing.JPopupMenu; |
3b2b638f | 23 | import javax.swing.SwingUtilities; |
4d205683 NR |
24 | import javax.swing.filechooser.FileFilter; |
25 | import javax.swing.filechooser.FileNameExtensionFilter; | |
a6395bef NR |
26 | |
27 | import be.nikiroo.fanfix.Instance; | |
e8eeea0a | 28 | import be.nikiroo.fanfix.bundles.Config; |
5bc9573b | 29 | import be.nikiroo.fanfix.bundles.StringIdGui; |
b4dc6ab5 | 30 | import be.nikiroo.fanfix.bundles.UiConfig; |
a6395bef | 31 | import be.nikiroo.fanfix.data.MetaData; |
4d205683 | 32 | import be.nikiroo.fanfix.data.Story; |
79a99506 | 33 | import be.nikiroo.fanfix.library.BasicLibrary; |
e42573a0 | 34 | import be.nikiroo.fanfix.library.LocalLibrary; |
4d205683 | 35 | import be.nikiroo.fanfix.output.BasicOutput.OutputType; |
16a81ef7 | 36 | import be.nikiroo.fanfix.reader.BasicReader; |
14bb95fa NR |
37 | import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.FrameHelper; |
38 | import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.StoryRunnable; | |
3b2b638f | 39 | import be.nikiroo.utils.Progress; |
39c3c689 | 40 | import be.nikiroo.utils.Version; |
e8eeea0a | 41 | import be.nikiroo.utils.ui.ConfigEditor; |
a6395bef | 42 | |
4d205683 | 43 | /** |
5dd985cf | 44 | * A {@link Frame} that will show a {@link GuiReaderBook} item for each |
4d205683 | 45 | * {@link Story} in the main cache ({@link Instance#getCache()}), and offer a |
5dd985cf NR |
46 | * way to copy them to the {@link GuiReader} cache ( |
47 | * {@link BasicReader#getLibrary()}), read them, delete them... | |
4d205683 NR |
48 | * |
49 | * @author niki | |
50 | */ | |
14bb95fa | 51 | class GuiReaderFrame extends JFrame implements FrameHelper { |
a6395bef | 52 | private static final long serialVersionUID = 1L; |
5dd985cf | 53 | private GuiReader reader; |
31e28683 | 54 | private GuiReaderMainPanel mainPanel; |
a6395bef | 55 | |
79a99506 NR |
56 | /** |
57 | * The different modification actions you can use on {@link Story} items. | |
58 | * | |
59 | * @author niki | |
60 | */ | |
61 | private enum ChangeAction { | |
62 | /** Change the source/type, that is, move it to another source. */ | |
63 | SOURCE, | |
64 | /** Change its name. */ | |
65 | TITLE, | |
66 | /** Change its author. */ | |
67 | AUTHOR | |
c8faa52a NR |
68 | } |
69 | ||
4d205683 | 70 | /** |
5dd985cf | 71 | * Create a new {@link GuiReaderFrame}. |
4d205683 NR |
72 | * |
73 | * @param reader | |
5dd985cf NR |
74 | * the associated {@link GuiReader} to forward some commands and |
75 | * access its {@link LocalLibrary} | |
4d205683 NR |
76 | * @param type |
77 | * the type of {@link Story} to load, or NULL for all types | |
78 | */ | |
5dd985cf | 79 | public GuiReaderFrame(GuiReader reader, String type) { |
5bc9573b | 80 | super(getAppTitle(reader.getLibrary().getLibraryName())); |
a6395bef NR |
81 | |
82 | this.reader = reader; | |
83 | ||
31e28683 | 84 | mainPanel = new GuiReaderMainPanel(this, type); |
4310bae9 | 85 | |
14bb95fa NR |
86 | setSize(800, 600); |
87 | setLayout(new BorderLayout()); | |
5beb7cdc | 88 | add(mainPanel, BorderLayout.CENTER); |
333f0e7b NR |
89 | } |
90 | ||
14bb95fa NR |
91 | @Override |
92 | public JPopupMenu createBookPopup() { | |
93 | JPopupMenu popup = new JPopupMenu(); | |
94 | popup.add(createMenuItemOpenBook()); | |
95 | popup.addSeparator(); | |
96 | popup.add(createMenuItemExport()); | |
97 | popup.add(createMenuItemMoveTo(true)); | |
79a99506 NR |
98 | popup.add(createMenuItemSetCoverForSource()); |
99 | popup.add(createMenuItemSetCoverForAuthor()); | |
14bb95fa NR |
100 | popup.add(createMenuItemClearCache()); |
101 | popup.add(createMenuItemRedownload()); | |
102 | popup.addSeparator(); | |
103 | popup.add(createMenuItemRename(true)); | |
104 | popup.add(createMenuItemSetAuthor(true)); | |
105 | popup.addSeparator(); | |
106 | popup.add(createMenuItemDelete()); | |
107 | popup.addSeparator(); | |
108 | popup.add(createMenuItemProperties()); | |
109 | return popup; | |
4310bae9 NR |
110 | } |
111 | ||
14bb95fa | 112 | @Override |
8590da19 | 113 | public JPopupMenu createSourceAuthorPopup() { |
14bb95fa NR |
114 | JPopupMenu popup = new JPopupMenu(); |
115 | popup.add(createMenuItemOpenBook()); | |
116 | return popup; | |
333f0e7b NR |
117 | } |
118 | ||
14bb95fa NR |
119 | @Override |
120 | public void createMenu(boolean libOk) { | |
32224dda N |
121 | invalidate(); |
122 | ||
14bb95fa | 123 | JMenuBar bar = new JMenuBar(); |
333f0e7b | 124 | |
5bc9573b | 125 | JMenu file = new JMenu(GuiReader.trans(StringIdGui.MENU_FILE)); |
10d558d2 | 126 | file.setMnemonic(KeyEvent.VK_F); |
333f0e7b | 127 | |
5bc9573b NR |
128 | JMenuItem imprt = new JMenuItem( |
129 | GuiReader.trans(StringIdGui.MENU_FILE_IMPORT_URL), | |
130 | KeyEvent.VK_U); | |
333f0e7b | 131 | imprt.addActionListener(new ActionListener() { |
211f7ddb | 132 | @Override |
333f0e7b | 133 | public void actionPerformed(ActionEvent e) { |
31e28683 | 134 | mainPanel.imprt(true); |
10d558d2 NR |
135 | } |
136 | }); | |
5bc9573b NR |
137 | JMenuItem imprtF = new JMenuItem( |
138 | GuiReader.trans(StringIdGui.MENU_FILE_IMPORT_FILE), | |
139 | KeyEvent.VK_F); | |
10d558d2 | 140 | imprtF.addActionListener(new ActionListener() { |
211f7ddb | 141 | @Override |
10d558d2 | 142 | public void actionPerformed(ActionEvent e) { |
31e28683 | 143 | mainPanel.imprt(false); |
10d558d2 NR |
144 | } |
145 | }); | |
5bc9573b NR |
146 | JMenuItem exit = new JMenuItem( |
147 | GuiReader.trans(StringIdGui.MENU_FILE_EXIT), KeyEvent.VK_X); | |
10d558d2 | 148 | exit.addActionListener(new ActionListener() { |
211f7ddb | 149 | @Override |
10d558d2 | 150 | public void actionPerformed(ActionEvent e) { |
5dd985cf NR |
151 | GuiReaderFrame.this.dispatchEvent(new WindowEvent( |
152 | GuiReaderFrame.this, WindowEvent.WINDOW_CLOSING)); | |
10d558d2 NR |
153 | } |
154 | }); | |
3b2b638f | 155 | |
9843a5e5 NR |
156 | file.add(createMenuItemOpenBook()); |
157 | file.add(createMenuItemExport()); | |
c8d48938 | 158 | file.add(createMenuItemMoveTo(libOk)); |
9843a5e5 | 159 | file.addSeparator(); |
10d558d2 NR |
160 | file.add(imprt); |
161 | file.add(imprtF); | |
162 | file.addSeparator(); | |
c8d48938 NR |
163 | file.add(createMenuItemRename(libOk)); |
164 | file.add(createMenuItemSetAuthor(libOk)); | |
165 | file.addSeparator(); | |
5bc9573b NR |
166 | file.add(createMenuItemProperties()); |
167 | file.addSeparator(); | |
10d558d2 | 168 | file.add(exit); |
3b2b638f | 169 | |
10d558d2 NR |
170 | bar.add(file); |
171 | ||
5bc9573b | 172 | JMenu edit = new JMenu(GuiReader.trans(StringIdGui.MENU_EDIT)); |
10d558d2 NR |
173 | edit.setMnemonic(KeyEvent.VK_E); |
174 | ||
5bc9573b NR |
175 | edit.add(createMenuItemSetCoverForSource()); |
176 | edit.add(createMenuItemSetCoverForAuthor()); | |
22848428 NR |
177 | edit.add(createMenuItemClearCache()); |
178 | edit.add(createMenuItemRedownload()); | |
9843a5e5 NR |
179 | edit.addSeparator(); |
180 | edit.add(createMenuItemDelete()); | |
181 | ||
182 | bar.add(edit); | |
183 | ||
5bc9573b | 184 | JMenu view = new JMenu(GuiReader.trans(StringIdGui.MENU_VIEW)); |
793f1071 | 185 | view.setMnemonic(KeyEvent.VK_V); |
5bc9573b NR |
186 | JMenuItem vauthors = new JMenuItem( |
187 | GuiReader.trans(StringIdGui.MENU_VIEW_AUTHOR)); | |
793f1071 NR |
188 | vauthors.setMnemonic(KeyEvent.VK_A); |
189 | vauthors.addActionListener(new ActionListener() { | |
211f7ddb | 190 | @Override |
793f1071 | 191 | public void actionPerformed(ActionEvent e) { |
31e28683 NR |
192 | mainPanel.setWords(false); |
193 | mainPanel.refreshBooks(); | |
793f1071 NR |
194 | } |
195 | }); | |
196 | view.add(vauthors); | |
5bc9573b NR |
197 | JMenuItem vwords = new JMenuItem( |
198 | GuiReader.trans(StringIdGui.MENU_VIEW_WCOUNT)); | |
793f1071 NR |
199 | vwords.setMnemonic(KeyEvent.VK_W); |
200 | vwords.addActionListener(new ActionListener() { | |
211f7ddb | 201 | @Override |
793f1071 | 202 | public void actionPerformed(ActionEvent e) { |
31e28683 NR |
203 | mainPanel.setWords(true); |
204 | mainPanel.refreshBooks(); | |
793f1071 NR |
205 | } |
206 | }); | |
207 | view.add(vwords); | |
208 | bar.add(view); | |
209 | ||
97b36d32 NR |
210 | Map<String, List<String>> groupedSources = new HashMap<String, List<String>>(); |
211 | if (libOk) { | |
212 | groupedSources = reader.getLibrary().getSourcesGrouped(); | |
213 | } | |
5bc9573b | 214 | JMenu sources = new JMenu(GuiReader.trans(StringIdGui.MENU_SOURCES)); |
4310bae9 | 215 | sources.setMnemonic(KeyEvent.VK_S); |
97b36d32 NR |
216 | populateMenuSA(sources, groupedSources, true); |
217 | bar.add(sources); | |
9843a5e5 | 218 | |
97b36d32 | 219 | Map<String, List<String>> goupedAuthors = new HashMap<String, List<String>>(); |
e6249b0f | 220 | if (libOk) { |
97b36d32 | 221 | goupedAuthors = reader.getLibrary().getAuthorsGrouped(); |
e6249b0f | 222 | } |
5bc9573b | 223 | JMenu authors = new JMenu(GuiReader.trans(StringIdGui.MENU_AUTHORS)); |
97b36d32 NR |
224 | authors.setMnemonic(KeyEvent.VK_A); |
225 | populateMenuSA(authors, goupedAuthors, false); | |
226 | bar.add(authors); | |
e6249b0f | 227 | |
5bc9573b | 228 | JMenu options = new JMenu(GuiReader.trans(StringIdGui.MENU_OPTIONS)); |
97b36d32 NR |
229 | options.setMnemonic(KeyEvent.VK_O); |
230 | options.add(createMenuItemConfig()); | |
231 | options.add(createMenuItemUiConfig()); | |
232 | bar.add(options); | |
c1b93db3 | 233 | |
14bb95fa | 234 | setJMenuBar(bar); |
97b36d32 NR |
235 | } |
236 | ||
237 | // "" = [unknown] | |
238 | private void populateMenuSA(JMenu menu, | |
239 | Map<String, List<String>> groupedValues, boolean type) { | |
240 | ||
5bc9573b NR |
241 | // "All" and "Listing" special items first |
242 | JMenuItem item = new JMenuItem(GuiReader.trans(StringIdGui.MENU_XXX_ALL_GROUPED)); | |
97b36d32 NR |
243 | item.addActionListener(getActionOpenList(type, false)); |
244 | menu.add(item); | |
5bc9573b | 245 | item = new JMenuItem(GuiReader.trans(StringIdGui.MENU_XXX_ALL_LISTING)); |
97b36d32 NR |
246 | item.addActionListener(getActionOpenList(type, true)); |
247 | menu.add(item); | |
5bc9573b | 248 | |
97b36d32 NR |
249 | menu.addSeparator(); |
250 | ||
251 | for (final String value : groupedValues.keySet()) { | |
252 | List<String> list = groupedValues.get(value); | |
253 | if (type && list.size() == 1 && list.get(0).isEmpty()) { | |
254 | // leaf item source/type | |
5bc9573b | 255 | item = new JMenuItem(value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value); |
97b36d32 NR |
256 | item.addActionListener(getActionOpen(value, type)); |
257 | menu.add(item); | |
c1b93db3 | 258 | } else { |
97b36d32 NR |
259 | JMenu dir; |
260 | if (!type && groupedValues.size() == 1) { | |
261 | // only one group of authors | |
262 | dir = menu; | |
263 | } else { | |
5bc9573b | 264 | dir = new JMenu(value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value); |
97b36d32 NR |
265 | } |
266 | ||
c1b93db3 NR |
267 | for (String sub : list) { |
268 | // " " instead of "" for the visual height | |
116904b8 NR |
269 | String itemName = sub; |
270 | if (itemName.isEmpty()) { | |
5bc9573b | 271 | itemName = type ? " " : GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN); |
116904b8 | 272 | } |
97b36d32 | 273 | |
116904b8 | 274 | String actualValue = value; |
97b36d32 NR |
275 | if (type) { |
276 | if (!sub.isEmpty()) { | |
277 | actualValue += "/" + sub; | |
278 | } | |
279 | } else { | |
280 | actualValue = sub; | |
c1b93db3 | 281 | } |
9843a5e5 | 282 | |
c1b93db3 | 283 | item = new JMenuItem(itemName); |
97b36d32 | 284 | item.addActionListener(getActionOpen(actualValue, type)); |
c1b93db3 NR |
285 | dir.add(item); |
286 | } | |
5f42f329 | 287 | |
97b36d32 NR |
288 | if (menu != dir) { |
289 | menu.add(dir); | |
290 | } | |
5f42f329 | 291 | } |
4310bae9 | 292 | } |
9843a5e5 NR |
293 | } |
294 | ||
c1b93db3 NR |
295 | /** |
296 | * Return an {@link ActionListener} that will set the given source (type) as | |
297 | * the selected/displayed one. | |
298 | * | |
299 | * @param type | |
97b36d32 | 300 | * the type (source) to select, cannot be NULL |
c1b93db3 NR |
301 | * |
302 | * @return the {@link ActionListener} | |
303 | */ | |
97b36d32 | 304 | private ActionListener getActionOpen(final String source, final boolean type) { |
c1b93db3 NR |
305 | return new ActionListener() { |
306 | @Override | |
307 | public void actionPerformed(ActionEvent e) { | |
31e28683 NR |
308 | mainPanel.removeBookPanes(); |
309 | mainPanel.addBookPane(source, type); | |
310 | mainPanel.refreshBooks(); | |
c1b93db3 NR |
311 | } |
312 | }; | |
313 | } | |
314 | ||
97b36d32 NR |
315 | private ActionListener getActionOpenList(final boolean type, |
316 | final boolean listMode) { | |
317 | return new ActionListener() { | |
318 | @Override | |
319 | public void actionPerformed(ActionEvent e) { | |
31e28683 NR |
320 | mainPanel.removeBookPanes(); |
321 | mainPanel.addBookPane(type, listMode); | |
322 | mainPanel.refreshBooks(); | |
5f42f329 | 323 | } |
97b36d32 | 324 | }; |
5f42f329 NR |
325 | } |
326 | ||
e8eeea0a NR |
327 | /** |
328 | * Create the Fanfix Configuration menu item. | |
329 | * | |
330 | * @return the item | |
331 | */ | |
332 | private JMenuItem createMenuItemConfig() { | |
5bc9573b | 333 | final String title = GuiReader.trans(StringIdGui.TITLE_CONFIG); |
e8eeea0a NR |
334 | JMenuItem item = new JMenuItem(title); |
335 | item.setMnemonic(KeyEvent.VK_F); | |
336 | ||
337 | item.addActionListener(new ActionListener() { | |
211f7ddb | 338 | @Override |
e8eeea0a NR |
339 | public void actionPerformed(ActionEvent e) { |
340 | ConfigEditor<Config> ed = new ConfigEditor<Config>( | |
341 | Config.class, Instance.getConfig(), | |
5bc9573b | 342 | GuiReader.trans(StringIdGui.SUBTITLE_CONFIG)); |
e8eeea0a NR |
343 | JFrame frame = new JFrame(title); |
344 | frame.add(ed); | |
345 | frame.setSize(800, 600); | |
346 | frame.setVisible(true); | |
347 | } | |
348 | }); | |
349 | ||
350 | return item; | |
351 | } | |
352 | ||
353 | /** | |
354 | * Create the UI Configuration menu item. | |
355 | * | |
356 | * @return the item | |
357 | */ | |
358 | private JMenuItem createMenuItemUiConfig() { | |
5bc9573b | 359 | final String title = GuiReader.trans(StringIdGui.TITLE_CONFIG_UI); |
e8eeea0a NR |
360 | JMenuItem item = new JMenuItem(title); |
361 | item.setMnemonic(KeyEvent.VK_U); | |
362 | ||
363 | item.addActionListener(new ActionListener() { | |
211f7ddb | 364 | @Override |
e8eeea0a NR |
365 | public void actionPerformed(ActionEvent e) { |
366 | ConfigEditor<UiConfig> ed = new ConfigEditor<UiConfig>( | |
367 | UiConfig.class, Instance.getUiConfig(), | |
5bc9573b | 368 | GuiReader.trans(StringIdGui.SUBTITLE_CONFIG_UI)); |
e8eeea0a NR |
369 | JFrame frame = new JFrame(title); |
370 | frame.add(ed); | |
371 | frame.setSize(800, 600); | |
372 | frame.setVisible(true); | |
373 | } | |
374 | }); | |
375 | ||
376 | return item; | |
377 | } | |
378 | ||
4d205683 NR |
379 | /** |
380 | * Create the export menu item. | |
381 | * | |
382 | * @return the item | |
383 | */ | |
9843a5e5 | 384 | private JMenuItem createMenuItemExport() { |
4d205683 NR |
385 | final JFileChooser fc = new JFileChooser(); |
386 | fc.setAcceptAllFileFilterUsed(false); | |
387 | ||
388 | final Map<FileFilter, OutputType> filters = new HashMap<FileFilter, OutputType>(); | |
389 | for (OutputType type : OutputType.values()) { | |
390 | String ext = type.getDefaultExtension(false); | |
391 | String desc = type.getDesc(false); | |
b2612f9d | 392 | |
4d205683 NR |
393 | if (ext == null || ext.isEmpty()) { |
394 | filters.put(createAllFilter(desc), type); | |
395 | } else { | |
396 | filters.put(new FileNameExtensionFilter(desc, ext), type); | |
397 | } | |
398 | } | |
399 | ||
400 | // First the "ALL" filters, then, the extension filters | |
401 | for (Entry<FileFilter, OutputType> entry : filters.entrySet()) { | |
402 | if (!(entry.getKey() instanceof FileNameExtensionFilter)) { | |
403 | fc.addChoosableFileFilter(entry.getKey()); | |
404 | } | |
405 | } | |
406 | for (Entry<FileFilter, OutputType> entry : filters.entrySet()) { | |
407 | if (entry.getKey() instanceof FileNameExtensionFilter) { | |
408 | fc.addChoosableFileFilter(entry.getKey()); | |
409 | } | |
410 | } | |
411 | // | |
9843a5e5 | 412 | |
5bc9573b | 413 | JMenuItem export = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_EXPORT), KeyEvent.VK_S); |
10d558d2 | 414 | export.addActionListener(new ActionListener() { |
211f7ddb | 415 | @Override |
10d558d2 | 416 | public void actionPerformed(ActionEvent e) { |
31e28683 | 417 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
4d205683 | 418 | if (selectedBook != null) { |
5bc9573b | 419 | fc.showDialog(GuiReaderFrame.this, GuiReader.trans(StringIdGui.TITLE_SAVE)); |
b2612f9d NR |
420 | if (fc.getSelectedFile() != null) { |
421 | final OutputType type = filters.get(fc.getFileFilter()); | |
422 | final String path = fc.getSelectedFile() | |
423 | .getAbsolutePath() | |
424 | + type.getDefaultExtension(false); | |
425 | final Progress pg = new Progress(); | |
2d56db73 | 426 | mainPanel.outOfUi(pg, false, new Runnable() { |
211f7ddb | 427 | @Override |
b2612f9d NR |
428 | public void run() { |
429 | try { | |
e42573a0 | 430 | reader.getLibrary().export( |
79a99506 NR |
431 | selectedBook.getInfo().getMeta() |
432 | .getLuid(), type, path, pg); | |
b2612f9d | 433 | } catch (IOException e) { |
62c63b07 | 434 | Instance.getTraceHandler().error(e); |
b2612f9d | 435 | } |
4d205683 | 436 | } |
b2612f9d NR |
437 | }); |
438 | } | |
4d205683 | 439 | } |
10d558d2 NR |
440 | } |
441 | }); | |
442 | ||
9843a5e5 NR |
443 | return export; |
444 | } | |
445 | ||
edd46289 NR |
446 | /** |
447 | * Create a {@link FileFilter} that accepts all files and return the given | |
448 | * description. | |
449 | * | |
450 | * @param desc | |
451 | * the description | |
452 | * | |
453 | * @return the filter | |
454 | */ | |
4d205683 NR |
455 | private FileFilter createAllFilter(final String desc) { |
456 | return new FileFilter() { | |
457 | @Override | |
458 | public String getDescription() { | |
459 | return desc; | |
460 | } | |
461 | ||
462 | @Override | |
463 | public boolean accept(File f) { | |
464 | return true; | |
465 | } | |
466 | }; | |
467 | } | |
468 | ||
469 | /** | |
470 | * Create the refresh (delete cache) menu item. | |
471 | * | |
472 | * @return the item | |
473 | */ | |
22848428 | 474 | private JMenuItem createMenuItemClearCache() { |
5bc9573b | 475 | JMenuItem refresh = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_CLEAR_CACHE), KeyEvent.VK_C); |
10d558d2 | 476 | refresh.addActionListener(new ActionListener() { |
211f7ddb | 477 | @Override |
10d558d2 | 478 | public void actionPerformed(ActionEvent e) { |
31e28683 | 479 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
10d558d2 | 480 | if (selectedBook != null) { |
2d56db73 | 481 | mainPanel.outOfUi(null, false, new Runnable() { |
211f7ddb | 482 | @Override |
10d558d2 | 483 | public void run() { |
79a99506 NR |
484 | reader.clearLocalReaderCache(selectedBook.getInfo() |
485 | .getMeta().getLuid()); | |
10d558d2 | 486 | selectedBook.setCached(false); |
df6e2d88 | 487 | GuiReaderCoverImager.clearIcon(selectedBook |
79a99506 | 488 | .getInfo()); |
3b2b638f | 489 | SwingUtilities.invokeLater(new Runnable() { |
211f7ddb | 490 | @Override |
3b2b638f | 491 | public void run() { |
10d558d2 | 492 | selectedBook.repaint(); |
3b2b638f NR |
493 | } |
494 | }); | |
495 | } | |
496 | }); | |
333f0e7b NR |
497 | } |
498 | } | |
499 | }); | |
10d558d2 | 500 | |
9843a5e5 NR |
501 | return refresh; |
502 | } | |
503 | ||
70c9b112 | 504 | /** |
c8d48938 | 505 | * Create the "move to" menu item. |
70c9b112 | 506 | * |
e6249b0f NR |
507 | * @param libOk |
508 | * the library can be queried | |
509 | * | |
70c9b112 NR |
510 | * @return the item |
511 | */ | |
c8d48938 | 512 | private JMenuItem createMenuItemMoveTo(boolean libOk) { |
5bc9573b | 513 | JMenu changeTo = new JMenu(GuiReader.trans(StringIdGui.MENU_FILE_MOVE_TO)); |
c8d48938 | 514 | changeTo.setMnemonic(KeyEvent.VK_M); |
70c9b112 | 515 | |
c1b93db3 | 516 | Map<String, List<String>> groupedSources = new HashMap<String, List<String>>(); |
e6249b0f | 517 | if (libOk) { |
c1b93db3 | 518 | groupedSources = reader.getLibrary().getSourcesGrouped(); |
e6249b0f | 519 | } |
70c9b112 | 520 | |
5bc9573b | 521 | JMenuItem item = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_TYPE)); |
79a99506 | 522 | item.addActionListener(createMoveAction(ChangeAction.SOURCE, null)); |
c1b93db3 NR |
523 | changeTo.add(item); |
524 | changeTo.addSeparator(); | |
70c9b112 | 525 | |
c1b93db3 NR |
526 | for (final String type : groupedSources.keySet()) { |
527 | List<String> list = groupedSources.get(type); | |
528 | if (list.size() == 1 && list.get(0).isEmpty()) { | |
529 | item = new JMenuItem(type); | |
79a99506 NR |
530 | item.addActionListener(createMoveAction(ChangeAction.SOURCE, |
531 | type)); | |
c1b93db3 NR |
532 | changeTo.add(item); |
533 | } else { | |
534 | JMenu dir = new JMenu(type); | |
535 | for (String sub : list) { | |
536 | // " " instead of "" for the visual height | |
537 | String itemName = sub.isEmpty() ? " " : sub; | |
538 | String actualType = type; | |
539 | if (!sub.isEmpty()) { | |
540 | actualType += "/" + sub; | |
541 | } | |
70c9b112 | 542 | |
c1b93db3 | 543 | item = new JMenuItem(itemName); |
79a99506 NR |
544 | item.addActionListener(createMoveAction( |
545 | ChangeAction.SOURCE, actualType)); | |
c1b93db3 NR |
546 | dir.add(item); |
547 | } | |
548 | changeTo.add(dir); | |
c8d48938 NR |
549 | } |
550 | } | |
211f7ddb | 551 | |
c8d48938 NR |
552 | return changeTo; |
553 | } | |
70c9b112 | 554 | |
c8d48938 NR |
555 | /** |
556 | * Create the "set author" menu item. | |
557 | * | |
558 | * @param libOk | |
559 | * the library can be queried | |
560 | * | |
561 | * @return the item | |
562 | */ | |
563 | private JMenuItem createMenuItemSetAuthor(boolean libOk) { | |
5bc9573b | 564 | JMenu changeTo = new JMenu(GuiReader.trans(StringIdGui.MENU_FILE_SET_AUTHOR)); |
c8d48938 | 565 | changeTo.setMnemonic(KeyEvent.VK_A); |
70c9b112 | 566 | |
c8d48938 | 567 | // New author |
5bc9573b | 568 | JMenuItem newItem = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_MOVE_TO_NEW_AUTHOR)); |
c8d48938 NR |
569 | changeTo.add(newItem); |
570 | changeTo.addSeparator(); | |
79a99506 | 571 | newItem.addActionListener(createMoveAction(ChangeAction.AUTHOR, null)); |
70c9b112 | 572 | |
c8d48938 NR |
573 | // Existing authors |
574 | if (libOk) { | |
97b36d32 NR |
575 | Map<String, List<String>> groupedAuthors = reader.getLibrary() |
576 | .getAuthorsGrouped(); | |
c8d48938 | 577 | |
97b36d32 NR |
578 | if (groupedAuthors.size() > 1) { |
579 | for (String key : groupedAuthors.keySet()) { | |
580 | JMenu group = new JMenu(key); | |
581 | for (String value : groupedAuthors.get(key)) { | |
116904b8 | 582 | JMenuItem item = new JMenuItem( |
5bc9573b | 583 | value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value); |
14bb95fa | 584 | item.addActionListener(createMoveAction( |
79a99506 | 585 | ChangeAction.AUTHOR, value)); |
c8d48938 | 586 | group.add(item); |
70c9b112 | 587 | } |
c8d48938 | 588 | changeTo.add(group); |
70c9b112 | 589 | } |
97b36d32 NR |
590 | } else if (groupedAuthors.size() == 1) { |
591 | for (String value : groupedAuthors.values().iterator().next()) { | |
116904b8 | 592 | JMenuItem item = new JMenuItem( |
5bc9573b | 593 | value.isEmpty() ? GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN) : value); |
79a99506 NR |
594 | item.addActionListener(createMoveAction( |
595 | ChangeAction.AUTHOR, value)); | |
c8d48938 NR |
596 | changeTo.add(item); |
597 | } | |
598 | } | |
70c9b112 NR |
599 | } |
600 | ||
c8d48938 NR |
601 | return changeTo; |
602 | } | |
603 | ||
604 | /** | |
605 | * Create the "rename" menu item. | |
606 | * | |
607 | * @param libOk | |
608 | * the library can be queried | |
609 | * | |
610 | * @return the item | |
611 | */ | |
612 | private JMenuItem createMenuItemRename( | |
613 | @SuppressWarnings("unused") boolean libOk) { | |
5bc9573b | 614 | JMenuItem changeTo = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_RENAME)); |
c8d48938 | 615 | changeTo.setMnemonic(KeyEvent.VK_R); |
79a99506 | 616 | changeTo.addActionListener(createMoveAction(ChangeAction.TITLE, null)); |
c8d48938 NR |
617 | return changeTo; |
618 | } | |
619 | ||
79a99506 | 620 | private ActionListener createMoveAction(final ChangeAction what, |
14bb95fa | 621 | final String type) { |
c8d48938 NR |
622 | return new ActionListener() { |
623 | @Override | |
624 | public void actionPerformed(ActionEvent e) { | |
31e28683 | 625 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
c8d48938 | 626 | if (selectedBook != null) { |
c349fd48 NR |
627 | boolean refreshRequired = false; |
628 | ||
629 | if (what == ChangeAction.SOURCE) { | |
630 | refreshRequired = mainPanel.getCurrentType(); | |
631 | } else if (what == ChangeAction.TITLE) { | |
632 | refreshRequired = false; | |
633 | } else if (what == ChangeAction.AUTHOR) { | |
634 | refreshRequired = !mainPanel.getCurrentType(); | |
635 | } | |
636 | ||
c8d48938 NR |
637 | String changeTo = type; |
638 | if (type == null) { | |
79a99506 | 639 | MetaData meta = selectedBook.getInfo().getMeta(); |
c8d48938 | 640 | String init = ""; |
79a99506 NR |
641 | if (what == ChangeAction.SOURCE) { |
642 | init = meta.getSource(); | |
643 | } else if (what == ChangeAction.TITLE) { | |
644 | init = meta.getTitle(); | |
645 | } else if (what == ChangeAction.AUTHOR) { | |
646 | init = meta.getAuthor(); | |
c8d48938 NR |
647 | } |
648 | ||
649 | Object rep = JOptionPane.showInputDialog( | |
5bc9573b NR |
650 | GuiReaderFrame.this, GuiReader.trans(StringIdGui.SUBTITLE_MOVE_TO), |
651 | GuiReader.trans(StringIdGui.TITLE_MOVE_TO), JOptionPane.QUESTION_MESSAGE, | |
c8d48938 NR |
652 | null, null, init); |
653 | ||
654 | if (rep == null) { | |
655 | return; | |
656 | } | |
657 | ||
658 | changeTo = rep.toString(); | |
659 | } | |
660 | ||
661 | final String fChangeTo = changeTo; | |
c349fd48 | 662 | mainPanel.outOfUi(null, refreshRequired, new Runnable() { |
c8d48938 NR |
663 | @Override |
664 | public void run() { | |
79a99506 NR |
665 | String luid = selectedBook.getInfo().getMeta() |
666 | .getLuid(); | |
667 | if (what == ChangeAction.SOURCE) { | |
668 | reader.changeSource(luid, fChangeTo); | |
669 | } else if (what == ChangeAction.TITLE) { | |
670 | reader.changeTitle(luid, fChangeTo); | |
671 | } else if (what == ChangeAction.AUTHOR) { | |
672 | reader.changeAuthor(luid, fChangeTo); | |
c8d48938 NR |
673 | } |
674 | ||
c349fd48 | 675 | mainPanel.getSelectedBook().repaint(); |
31e28683 | 676 | mainPanel.unsetSelectedBook(); |
c8d48938 NR |
677 | |
678 | SwingUtilities.invokeLater(new Runnable() { | |
679 | @Override | |
680 | public void run() { | |
14bb95fa | 681 | createMenu(true); |
c8d48938 NR |
682 | } |
683 | }); | |
684 | } | |
685 | }); | |
686 | } | |
687 | } | |
688 | }; | |
70c9b112 NR |
689 | } |
690 | ||
22848428 | 691 | /** |
79a99506 | 692 | * Create the re-download (then delete original) menu item. |
22848428 NR |
693 | * |
694 | * @return the item | |
695 | */ | |
696 | private JMenuItem createMenuItemRedownload() { | |
5bc9573b | 697 | JMenuItem refresh = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_REDOWNLOAD), KeyEvent.VK_R); |
22848428 | 698 | refresh.addActionListener(new ActionListener() { |
211f7ddb | 699 | @Override |
22848428 | 700 | public void actionPerformed(ActionEvent e) { |
31e28683 | 701 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
22848428 | 702 | if (selectedBook != null) { |
79a99506 | 703 | final MetaData meta = selectedBook.getInfo().getMeta(); |
31e28683 | 704 | mainPanel.imprt(meta.getUrl(), new StoryRunnable() { |
211f7ddb | 705 | @Override |
c8faa52a | 706 | public void run(Story story) { |
754a5bc2 | 707 | reader.delete(meta.getLuid()); |
31e28683 | 708 | mainPanel.unsetSelectedBook(); |
c8faa52a NR |
709 | MetaData newMeta = story.getMeta(); |
710 | if (!newMeta.getSource().equals(meta.getSource())) { | |
c3b229a1 | 711 | reader.changeSource(newMeta.getLuid(), |
c8faa52a NR |
712 | meta.getSource()); |
713 | } | |
22848428 | 714 | } |
5bc9573b | 715 | }, GuiReader.trans(StringIdGui.PROGRESS_REDOWNLOAD_REMOVE_OLD_COPY)); |
22848428 NR |
716 | } |
717 | } | |
718 | }); | |
719 | ||
720 | return refresh; | |
721 | } | |
722 | ||
4d205683 NR |
723 | /** |
724 | * Create the delete menu item. | |
725 | * | |
726 | * @return the item | |
727 | */ | |
9843a5e5 | 728 | private JMenuItem createMenuItemDelete() { |
5bc9573b | 729 | JMenuItem delete = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_DELETE), KeyEvent.VK_D); |
10d558d2 | 730 | delete.addActionListener(new ActionListener() { |
211f7ddb | 731 | @Override |
10d558d2 | 732 | public void actionPerformed(ActionEvent e) { |
31e28683 | 733 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
c349fd48 NR |
734 | if (selectedBook != null |
735 | && selectedBook.getInfo().getMeta() != null) { | |
736 | ||
737 | final MetaData meta = selectedBook.getInfo().getMeta(); | |
738 | int rep = JOptionPane.showConfirmDialog( | |
739 | GuiReaderFrame.this, | |
5bc9573b NR |
740 | GuiReader.trans(StringIdGui.SUBTITLE_DELETE, meta.getLuid(), |
741 | meta.getTitle()), GuiReader.trans(StringIdGui.TITLE_DELETE), | |
c349fd48 NR |
742 | JOptionPane.OK_CANCEL_OPTION); |
743 | ||
744 | if (rep == JOptionPane.OK_OPTION) { | |
745 | mainPanel.outOfUi(null, true, new Runnable() { | |
746 | @Override | |
747 | public void run() { | |
748 | reader.delete(meta.getLuid()); | |
749 | mainPanel.unsetSelectedBook(); | |
750 | } | |
751 | }); | |
752 | } | |
10d558d2 NR |
753 | } |
754 | } | |
755 | }); | |
756 | ||
9843a5e5 NR |
757 | return delete; |
758 | } | |
10d558d2 | 759 | |
df6e2d88 NR |
760 | /** |
761 | * Create the properties menu item. | |
762 | * | |
763 | * @return the item | |
764 | */ | |
765 | private JMenuItem createMenuItemProperties() { | |
5bc9573b | 766 | JMenuItem delete = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_PROPERTIES), KeyEvent.VK_P); |
df6e2d88 NR |
767 | delete.addActionListener(new ActionListener() { |
768 | @Override | |
769 | public void actionPerformed(ActionEvent e) { | |
31e28683 | 770 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
df6e2d88 | 771 | if (selectedBook != null) { |
2d56db73 | 772 | mainPanel.outOfUi(null, false, new Runnable() { |
df6e2d88 NR |
773 | @Override |
774 | public void run() { | |
5beb7cdc NR |
775 | new GuiReaderPropertiesFrame(reader.getLibrary(), |
776 | selectedBook.getInfo().getMeta()) | |
777 | .setVisible(true); | |
df6e2d88 NR |
778 | } |
779 | }); | |
780 | } | |
781 | } | |
782 | }); | |
783 | ||
784 | return delete; | |
785 | } | |
786 | ||
4d205683 | 787 | /** |
32224dda | 788 | * Create the open menu item for a book, a source/type or an author. |
4d205683 NR |
789 | * |
790 | * @return the item | |
791 | */ | |
14bb95fa | 792 | public JMenuItem createMenuItemOpenBook() { |
5bc9573b | 793 | JMenuItem open = new JMenuItem(GuiReader.trans(StringIdGui.MENU_FILE_OPEN), KeyEvent.VK_O); |
9843a5e5 | 794 | open.addActionListener(new ActionListener() { |
211f7ddb | 795 | @Override |
9843a5e5 | 796 | public void actionPerformed(ActionEvent e) { |
31e28683 | 797 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
9843a5e5 | 798 | if (selectedBook != null) { |
8590da19 | 799 | if (selectedBook.getInfo().getMeta() == null) { |
31e28683 | 800 | mainPanel.removeBookPanes(); |
5beb7cdc NR |
801 | mainPanel.addBookPane(selectedBook.getInfo() |
802 | .getMainInfo(), mainPanel.getCurrentType()); | |
31e28683 | 803 | mainPanel.refreshBooks(); |
14b57448 | 804 | } else { |
31e28683 | 805 | mainPanel.openBook(selectedBook); |
14b57448 NR |
806 | } |
807 | } | |
808 | } | |
809 | }); | |
810 | ||
811 | return open; | |
812 | } | |
813 | ||
814 | /** | |
815 | * Create the SetCover menu item for a book to change the linked source | |
816 | * cover. | |
817 | * | |
818 | * @return the item | |
819 | */ | |
79a99506 | 820 | private JMenuItem createMenuItemSetCoverForSource() { |
5bc9573b | 821 | JMenuItem open = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_SOURCE), KeyEvent.VK_C); |
14b57448 NR |
822 | open.addActionListener(new ActionListener() { |
823 | @Override | |
824 | public void actionPerformed(ActionEvent e) { | |
31e28683 | 825 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); |
14b57448 | 826 | if (selectedBook != null) { |
79a99506 NR |
827 | BasicLibrary lib = reader.getLibrary(); |
828 | String luid = selectedBook.getInfo().getMeta().getLuid(); | |
829 | String source = selectedBook.getInfo().getMeta() | |
830 | .getSource(); | |
831 | ||
832 | lib.setSourceCover(source, luid); | |
833 | ||
834 | GuiReaderBookInfo sourceInfo = GuiReaderBookInfo | |
835 | .fromSource(lib, source); | |
836 | GuiReaderCoverImager.clearIcon(sourceInfo); | |
837 | } | |
838 | } | |
839 | }); | |
840 | ||
841 | return open; | |
842 | } | |
843 | ||
844 | /** | |
845 | * Create the SetCover menu item for a book to change the linked source | |
846 | * cover. | |
847 | * | |
848 | * @return the item | |
849 | */ | |
850 | private JMenuItem createMenuItemSetCoverForAuthor() { | |
5bc9573b | 851 | JMenuItem open = new JMenuItem(GuiReader.trans(StringIdGui.MENU_EDIT_SET_COVER_FOR_AUTHOR), KeyEvent.VK_A); |
79a99506 NR |
852 | open.addActionListener(new ActionListener() { |
853 | @Override | |
854 | public void actionPerformed(ActionEvent e) { | |
855 | final GuiReaderBook selectedBook = mainPanel.getSelectedBook(); | |
856 | if (selectedBook != null) { | |
857 | BasicLibrary lib = reader.getLibrary(); | |
858 | String luid = selectedBook.getInfo().getMeta().getLuid(); | |
859 | String author = selectedBook.getInfo().getMeta() | |
860 | .getAuthor(); | |
861 | ||
862 | lib.setAuthorCover(author, luid); | |
863 | ||
864 | GuiReaderBookInfo authorInfo = GuiReaderBookInfo | |
865 | .fromAuthor(lib, author); | |
866 | GuiReaderCoverImager.clearIcon(authorInfo); | |
9843a5e5 NR |
867 | } |
868 | } | |
869 | }); | |
10d558d2 | 870 | |
9843a5e5 NR |
871 | return open; |
872 | } | |
10d558d2 | 873 | |
e6249b0f NR |
874 | /** |
875 | * Display an error message and log the linked {@link Exception}. | |
876 | * | |
877 | * @param message | |
878 | * the message | |
879 | * @param title | |
880 | * the title of the error message | |
881 | * @param e | |
882 | * the exception to log if any | |
883 | */ | |
14bb95fa | 884 | public void error(final String message, final String title, Exception e) { |
e6249b0f NR |
885 | Instance.getTraceHandler().error(title + ": " + message); |
886 | if (e != null) { | |
887 | Instance.getTraceHandler().error(e); | |
888 | } | |
889 | ||
890 | SwingUtilities.invokeLater(new Runnable() { | |
891 | @Override | |
892 | public void run() { | |
893 | JOptionPane.showMessageDialog(GuiReaderFrame.this, message, | |
894 | title, JOptionPane.ERROR_MESSAGE); | |
895 | } | |
896 | }); | |
897 | } | |
14bb95fa NR |
898 | |
899 | @Override | |
900 | public GuiReader getReader() { | |
901 | return reader; | |
902 | } | |
5bc9573b NR |
903 | |
904 | /** | |
905 | * Return the title of the application. | |
906 | * | |
907 | * @param libraryName | |
908 | * the name of the associated {@link BasicLibrary}, which can be | |
909 | * EMPTY | |
910 | * | |
911 | * @return the title | |
912 | */ | |
913 | static private String getAppTitle(String libraryName) { | |
914 | if (!libraryName.isEmpty()) { | |
915 | return GuiReader.trans(StringIdGui.TITLE_LIBRARY_WITH_NAME, Version | |
916 | .getCurrentVersion().toString(), libraryName); | |
917 | } | |
918 | ||
919 | return GuiReader.trans(StringIdGui.TITLE_LIBRARY, Version.getCurrentVersion() | |
920 | .toString()); | |
921 | } | |
a6395bef | 922 | } |