GUI: disable search for now
[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;
99e1c5ec
NR
39import be.nikiroo.fanfix.searchable.BasicSearchable;
40import be.nikiroo.fanfix.supported.SupportType;
3b2b638f 41import be.nikiroo.utils.Progress;
39c3c689 42import be.nikiroo.utils.Version;
e8eeea0a 43import 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 53class 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}