gui: French translation
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderFrame.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.ui;
a6395bef 2
d3c84ac3 3import java.awt.BorderLayout;
4d205683 4import java.awt.Frame;
a6395bef
NR
5import java.awt.event.ActionEvent;
6import java.awt.event.ActionListener;
333f0e7b
NR
7import java.awt.event.KeyEvent;
8import java.awt.event.WindowEvent;
9import java.io.File;
a6395bef 10import java.io.IOException;
4d205683 11import java.util.HashMap;
a6395bef 12import java.util.List;
4d205683
NR
13import java.util.Map;
14import java.util.Map.Entry;
a6395bef 15
10d558d2 16import javax.swing.JFileChooser;
a6395bef 17import javax.swing.JFrame;
333f0e7b
NR
18import javax.swing.JMenu;
19import javax.swing.JMenuBar;
20import javax.swing.JMenuItem;
21import javax.swing.JOptionPane;
9843a5e5 22import javax.swing.JPopupMenu;
3b2b638f 23import javax.swing.SwingUtilities;
4d205683
NR
24import javax.swing.filechooser.FileFilter;
25import javax.swing.filechooser.FileNameExtensionFilter;
a6395bef
NR
26
27import be.nikiroo.fanfix.Instance;
e8eeea0a 28import be.nikiroo.fanfix.bundles.Config;
5bc9573b 29import be.nikiroo.fanfix.bundles.StringIdGui;
b4dc6ab5 30import be.nikiroo.fanfix.bundles.UiConfig;
a6395bef 31import be.nikiroo.fanfix.data.MetaData;
4d205683 32import be.nikiroo.fanfix.data.Story;
79a99506 33import be.nikiroo.fanfix.library.BasicLibrary;
e42573a0 34import be.nikiroo.fanfix.library.LocalLibrary;
4d205683 35import be.nikiroo.fanfix.output.BasicOutput.OutputType;
16a81ef7 36import be.nikiroo.fanfix.reader.BasicReader;
14bb95fa
NR
37import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.FrameHelper;
38import be.nikiroo.fanfix.reader.ui.GuiReaderMainPanel.StoryRunnable;
3b2b638f 39import be.nikiroo.utils.Progress;
39c3c689 40import be.nikiroo.utils.Version;
e8eeea0a 41import 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 51class 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}