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