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