import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Font;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.util.Map;
import java.util.Map.Entry;
+import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
lib.refresh(pg);
invalidate();
setJMenuBar(createMenu(true));
- addBookPane(typeF, true);
+ if (typeF == null) {
+ addBookPane(true, false);
+ } else {
+ addBookPane(typeF, true);
+ }
refreshBooks();
validate();
pane.setVisible(true);
setVisible(true);
}
- private void addSourcePanes() {
+ private void addListPane(String name, List<String> values,
+ final boolean type) {
// Sources -> i18n
- GuiReaderGroup bookPane = new GuiReaderGroup(reader, "Sources", color);
+ GuiReaderGroup bookPane = new GuiReaderGroup(reader, name, color);
- List<MetaData> sources = new ArrayList<MetaData>();
- for (String source : reader.getLibrary().getSources()) {
+ List<MetaData> metas = new ArrayList<MetaData>();
+ for (String source : values) {
MetaData mSource = new MetaData();
mSource.setLuid(null);
mSource.setTitle(source);
mSource.setSource(source);
- sources.add(mSource);
+ metas.add(mSource);
}
- bookPane.refreshBooks(sources, false);
+ bookPane.refreshBooks(metas, false);
this.invalidate();
pane.invalidate();
@Override
public void action(final GuiReaderBook book) {
removeBookPanes();
- addBookPane(book.getMeta().getSource(), true);
+ addBookPane(book.getMeta().getSource(), type);
refreshBooks();
}
});
}
/**
- * Add a new {@link GuiReaderGroup} on the frame to display the books of the
- * selected type or author.
+ * Add a new {@link GuiReaderGroup} on the frame to display all the
+ * sources/types or all the authors, or a listing of all the books sorted
+ * either by source or author.
+ * <p>
+ * A display of all the sources/types or all the authors will show one icon
+ * per source/type or author.
+ * <p>
+ * A listing of all the books sorted by source/type or author will display
+ * all the books.
*
- * @param value
- * the author or the type, or NULL to get all the
- * authors-or-types
* @param type
- * TRUE for type, FALSE for author
+ * TRUE for type/source, FALSE for author
+ * @param listMode
+ * TRUE to get a listing of all the sources or authors, FALSE to
+ * get one icon per source or author
*/
- private void addBookPane(String value, boolean type) {
- if (value == null) {
- if (type) {
- if (Instance.getUiConfig().getBoolean(UiConfig.SOURCE_PAGE,
- false)) {
- addSourcePanes();
- } else {
- for (String tt : reader.getLibrary().getSources()) {
- if (tt != null) {
- addBookPane(tt, type);
- }
+ private void addBookPane(boolean type, boolean listMode) {
+ if (type) {
+ if (!listMode) {
+ addListPane("Sources", reader.getLibrary().getSources(), type);
+ } else {
+ for (String tt : reader.getLibrary().getSources()) {
+ if (tt != null) {
+ addBookPane(tt, type);
}
}
+ }
+ } else {
+ if (!listMode) {
+ addListPane("Authors", reader.getLibrary().getAuthors(), type);
} else {
for (String tt : reader.getLibrary().getAuthors()) {
if (tt != null) {
}
}
}
-
- return;
}
+ }
+ /**
+ * Add a new {@link GuiReaderGroup} on the frame to display the books of the
+ * selected type or author.
+ *
+ * @param value
+ * the author or the type, or NULL to get all the
+ * authors-or-types
+ * @param type
+ * TRUE for type/source, FALSE for author
+ *
+ */
+ private void addBookPane(String value, boolean type) {
GuiReaderGroup bookPane = new GuiReaderGroup(reader, value, color);
if (type) {
booksByType.put(bookPane, value);
popup.add(createMenuItemOpenBook());
popup.addSeparator();
popup.add(createMenuItemExport());
- popup.add(createMenuItemMove(true));
+ popup.add(createMenuItemMoveTo(true));
popup.add(createMenuItemSetCover());
popup.add(createMenuItemClearCache());
popup.add(createMenuItemRedownload());
popup.addSeparator();
+ popup.add(createMenuItemRename(true));
+ popup.add(createMenuItemSetAuthor(true));
+ popup.addSeparator();
popup.add(createMenuItemDelete());
+ popup.addSeparator();
+ popup.add(createMenuItemProperties());
popup.show(e.getComponent(), e.getX(), e.getY());
}
});
}
+ /**
+ * Clear the pane from any book that may be present, usually prior to adding
+ * new ones.
+ */
private void removeBookPanes() {
booksByType.clear();
booksByAuthor.clear();
file.add(createMenuItemOpenBook());
file.add(createMenuItemExport());
- file.add(createMenuItemMove(libOk));
+ file.add(createMenuItemMoveTo(libOk));
file.addSeparator();
file.add(imprt);
file.add(imprtF);
file.addSeparator();
+ file.add(createMenuItemRename(libOk));
+ file.add(createMenuItemSetAuthor(libOk));
+ file.addSeparator();
file.add(exit);
bar.add(file);
view.add(vwords);
bar.add(view);
+ Map<String, List<String>> groupedSources = new HashMap<String, List<String>>();
+ if (libOk) {
+ groupedSources = reader.getLibrary().getSourcesGrouped();
+ }
JMenu sources = new JMenu("Sources");
sources.setMnemonic(KeyEvent.VK_S);
+ populateMenuSA(sources, groupedSources, true);
+ bar.add(sources);
- List<String> tt = new ArrayList<String>();
+ Map<String, List<String>> goupedAuthors = new HashMap<String, List<String>>();
if (libOk) {
- tt.addAll(reader.getLibrary().getSources());
+ goupedAuthors = reader.getLibrary().getAuthorsGrouped();
}
- tt.add(0, null);
-
- for (final String type : tt) {
- JMenuItem item = new JMenuItem(type == null ? "All" : type);
- item.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- removeBookPanes();
- addBookPane(type, true);
- refreshBooks();
- }
- });
- sources.add(item);
-
- if (type == null) {
- sources.addSeparator();
- }
- }
-
- bar.add(sources);
-
JMenu authors = new JMenu("Authors");
authors.setMnemonic(KeyEvent.VK_A);
-
- List<String> aa = new ArrayList<String>();
- if (libOk) {
- aa.addAll(reader.getLibrary().getAuthors());
- }
- aa.add(0, null);
- for (final String author : aa) {
- JMenuItem item = new JMenuItem(author == null ? "All"
- : author.isEmpty() ? "[unknown]" : author);
- item.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- removeBookPanes();
- addBookPane(author, false);
- refreshBooks();
- }
- });
- authors.add(item);
-
- if (author == null || author.isEmpty()) {
- authors.addSeparator();
- }
- }
-
+ populateMenuSA(authors, goupedAuthors, false);
bar.add(authors);
JMenu options = new JMenu("Options");
return bar;
}
+ // "" = [unknown]
+ private void populateMenuSA(JMenu menu,
+ Map<String, List<String>> groupedValues, boolean type) {
+
+ // "All" and "Listing" special items
+ JMenuItem item = new JMenuItem("All");
+ item.addActionListener(getActionOpenList(type, false));
+ menu.add(item);
+ item = new JMenuItem("Listing");
+ item.addActionListener(getActionOpenList(type, true));
+ menu.add(item);
+ menu.addSeparator();
+
+ for (final String value : groupedValues.keySet()) {
+ List<String> list = groupedValues.get(value);
+ if (type && list.size() == 1 && list.get(0).isEmpty()) {
+ // leaf item source/type
+ item = new JMenuItem(value.isEmpty() ? "[unknown]" : value);
+ item.addActionListener(getActionOpen(value, type));
+ menu.add(item);
+ } else {
+ JMenu dir;
+ if (!type && groupedValues.size() == 1) {
+ // only one group of authors
+ dir = menu;
+ } else {
+ dir = new JMenu(value.isEmpty() ? "[unknown]" : value);
+ }
+
+ for (String sub : list) {
+ // " " instead of "" for the visual height
+ String itemName = sub.isEmpty() ? " " : sub;
+ String actualValue = value;
+
+ if (type) {
+ if (!sub.isEmpty()) {
+ actualValue += "/" + sub;
+ }
+ } else {
+ actualValue = sub;
+ }
+
+ item = new JMenuItem(itemName);
+ item.addActionListener(getActionOpen(actualValue, type));
+ dir.add(item);
+ }
+
+ if (menu != dir) {
+ menu.add(dir);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return an {@link ActionListener} that will set the given source (type) as
+ * the selected/displayed one.
+ *
+ * @param type
+ * the type (source) to select, cannot be NULL
+ *
+ * @return the {@link ActionListener}
+ */
+ private ActionListener getActionOpen(final String source, final boolean type) {
+ return new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ removeBookPanes();
+ addBookPane(source, type);
+ refreshBooks();
+ }
+ };
+ }
+
+ private ActionListener getActionOpenList(final boolean type,
+ final boolean listMode) {
+ return new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ removeBookPanes();
+ addBookPane(type, listMode);
+ refreshBooks();
+ }
+ };
+ }
+
/**
* Create the Fanfix Configuration menu item.
*
reader.clearLocalReaderCache(selectedBook.getMeta()
.getLuid());
selectedBook.setCached(false);
- GuiReaderBook.clearIcon(selectedBook.getMeta());
+ GuiReaderCoverImager.clearIcon(selectedBook
+ .getMeta());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
}
/**
- * Create the delete menu item.
+ * Create the "move to" menu item.
*
* @param libOk
* the library can be queried
*
* @return the item
*/
- private JMenuItem createMenuItemMove(boolean libOk) {
- JMenu moveTo = new JMenu("Move to...");
- moveTo.setMnemonic(KeyEvent.VK_M);
+ private JMenuItem createMenuItemMoveTo(boolean libOk) {
+ JMenu changeTo = new JMenu("Move to");
+ changeTo.setMnemonic(KeyEvent.VK_M);
- List<String> types = new ArrayList<String>();
- types.add(null);
+ Map<String, List<String>> groupedSources = new HashMap<String, List<String>>();
if (libOk) {
- types.addAll(reader.getLibrary().getSources());
+ groupedSources = reader.getLibrary().getSourcesGrouped();
}
- for (String type : types) {
- JMenuItem item = new JMenuItem(type == null ? "New type..." : type);
+ JMenuItem item = new JMenuItem("New type...");
+ item.addActionListener(createMoveAction("SOURCE", null));
+ changeTo.add(item);
+ changeTo.addSeparator();
+
+ for (final String type : groupedSources.keySet()) {
+ List<String> list = groupedSources.get(type);
+ if (list.size() == 1 && list.get(0).isEmpty()) {
+ item = new JMenuItem(type);
+ item.addActionListener(createMoveAction("SOURCE", type));
+ changeTo.add(item);
+ } else {
+ JMenu dir = new JMenu(type);
+ for (String sub : list) {
+ // " " instead of "" for the visual height
+ String itemName = sub.isEmpty() ? " " : sub;
+ String actualType = type;
+ if (!sub.isEmpty()) {
+ actualType += "/" + sub;
+ }
- moveTo.add(item);
- if (type == null) {
- moveTo.addSeparator();
+ item = new JMenuItem(itemName);
+ item.addActionListener(createMoveAction("SOURCE",
+ actualType));
+ dir.add(item);
+ }
+ changeTo.add(dir);
}
+ }
- final String ftype = type;
- item.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- if (selectedBook != null) {
- String type = ftype;
- if (type == null) {
- Object rep = JOptionPane.showInputDialog(
- GuiReaderFrame.this, "Move to:",
- "Moving story",
- JOptionPane.QUESTION_MESSAGE, null, null,
- selectedBook.getMeta().getSource());
-
- if (rep == null) {
- return;
- }
-
- type = rep.toString();
- }
+ return changeTo;
+ }
- final String ftype = type;
- outOfUi(null, new Runnable() {
- @Override
- public void run() {
- reader.changeSource(selectedBook.getMeta()
- .getLuid(), ftype);
+ /**
+ * Create the "set author" menu item.
+ *
+ * @param libOk
+ * the library can be queried
+ *
+ * @return the item
+ */
+ private JMenuItem createMenuItemSetAuthor(boolean libOk) {
+ JMenu changeTo = new JMenu("Set author");
+ changeTo.setMnemonic(KeyEvent.VK_A);
- selectedBook = null;
+ // New author
+ JMenuItem newItem = new JMenuItem("New author...");
+ changeTo.add(newItem);
+ changeTo.addSeparator();
+ newItem.addActionListener(createMoveAction("AUTHOR", null));
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- setJMenuBar(createMenu(true));
- }
- });
- }
- });
+ // Existing authors
+ if (libOk) {
+ Map<String, List<String>> groupedAuthors = reader.getLibrary()
+ .getAuthorsGrouped();
+
+ if (groupedAuthors.size() > 1) {
+ for (String key : groupedAuthors.keySet()) {
+ JMenu group = new JMenu(key);
+ for (String value : groupedAuthors.get(key)) {
+ JMenuItem item = new JMenuItem(value);
+ item.addActionListener(createMoveAction("AUTHOR", value));
+ group.add(item);
}
+ changeTo.add(group);
+ }
+ } else if (groupedAuthors.size() == 1) {
+ for (String value : groupedAuthors.values().iterator().next()) {
+ JMenuItem item = new JMenuItem(value);
+ item.addActionListener(createMoveAction("AUTHOR", value));
+ changeTo.add(item);
}
- });
+ }
}
- return moveTo;
+ return changeTo;
+ }
+
+ /**
+ * Create the "rename" menu item.
+ *
+ * @param libOk
+ * the library can be queried
+ *
+ * @return the item
+ */
+ private JMenuItem createMenuItemRename(
+ @SuppressWarnings("unused") boolean libOk) {
+ JMenuItem changeTo = new JMenuItem("Rename...");
+ changeTo.setMnemonic(KeyEvent.VK_R);
+ changeTo.addActionListener(createMoveAction("TITLE", null));
+ return changeTo;
+ }
+
+ private ActionListener createMoveAction(final String what, final String type) {
+ return new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (selectedBook != null) {
+ String changeTo = type;
+ if (type == null) {
+ String init = "";
+ if (what.equals("SOURCE")) {
+ init = selectedBook.getMeta().getSource();
+ } else if (what.equals("TITLE")) {
+ init = selectedBook.getMeta().getTitle();
+ } else if (what.equals("AUTHOR")) {
+ init = selectedBook.getMeta().getAuthor();
+ }
+
+ Object rep = JOptionPane.showInputDialog(
+ GuiReaderFrame.this, "Move to:",
+ "Moving story", JOptionPane.QUESTION_MESSAGE,
+ null, null, init);
+
+ if (rep == null) {
+ return;
+ }
+
+ changeTo = rep.toString();
+ }
+
+ final String fChangeTo = changeTo;
+ outOfUi(null, new Runnable() {
+ @Override
+ public void run() {
+ if (what.equals("SOURCE")) {
+ reader.changeSource(selectedBook.getMeta()
+ .getLuid(), fChangeTo);
+ } else if (what.equals("TITLE")) {
+ reader.changeTitle(selectedBook.getMeta()
+ .getLuid(), fChangeTo);
+ } else if (what.equals("AUTHOR")) {
+ reader.changeAuthor(selectedBook.getMeta()
+ .getLuid(), fChangeTo);
+ }
+
+ selectedBook = null;
+
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ setJMenuBar(createMenu(true));
+ }
+ });
+ }
+ });
+ }
+ }
+ };
}
/**
return delete;
}
+ /**
+ * Create the properties menu item.
+ *
+ * @return the item
+ */
+ private JMenuItem createMenuItemProperties() {
+ JMenuItem delete = new JMenuItem("Properties", KeyEvent.VK_P);
+ delete.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (selectedBook != null) {
+ outOfUi(null, new Runnable() {
+ @Override
+ public void run() {
+ final MetaData meta = selectedBook.getMeta();
+ new JFrame() {
+ private static final long serialVersionUID = 1L;
+ @SuppressWarnings("unused")
+ private Object init = init();
+
+ private Object init() {
+ // Borders
+ int top = 20;
+ int space = 10;
+
+ // Image
+ ImageIcon img = GuiReaderCoverImager
+ .generateCoverIcon(
+ reader.getLibrary(), meta);
+
+ // frame
+ setTitle(meta.getLuid() + ": "
+ + meta.getTitle());
+
+ setSize(800, img.getIconHeight() + 2 * top);
+ setLayout(new BorderLayout());
+
+ // Main panel
+ JPanel mainPanel = new JPanel(
+ new BorderLayout());
+ JPanel mainPanelKeys = new JPanel();
+ mainPanelKeys.setLayout(new BoxLayout(
+ mainPanelKeys, BoxLayout.Y_AXIS));
+ JPanel mainPanelValues = new JPanel();
+ mainPanelValues.setLayout(new BoxLayout(
+ mainPanelValues, BoxLayout.Y_AXIS));
+
+ mainPanel.add(mainPanelKeys,
+ BorderLayout.WEST);
+ mainPanel.add(mainPanelValues,
+ BorderLayout.CENTER);
+
+ List<Entry<String, String>> infos = BasicReader
+ .getMetaDesc(meta);
+
+ Color trans = new Color(0, 0, 0, 1);
+ for (Entry<String, String> info : infos) {
+ JTextArea key = new JTextArea(info
+ .getKey());
+ key.setFont(new Font(key.getFont()
+ .getFontName(), Font.BOLD, key
+ .getFont().getSize()));
+ key.setEditable(false);
+ key.setLineWrap(false);
+ key.setBackground(trans);
+ mainPanelKeys.add(key);
+
+ JTextArea value = new JTextArea(info
+ .getValue());
+ value.setEditable(false);
+ value.setLineWrap(false);
+ value.setBackground(trans);
+ mainPanelValues.add(value);
+ }
+
+ // Image
+ JLabel imgLabel = new JLabel(img);
+ imgLabel.setVerticalAlignment(JLabel.TOP);
+
+ // Borders
+ mainPanelKeys.setBorder(BorderFactory
+ .createEmptyBorder(top, space, 0, 0));
+ mainPanelValues.setBorder(BorderFactory
+ .createEmptyBorder(top, space, 0, 0));
+ imgLabel.setBorder(BorderFactory
+ .createEmptyBorder(0, space, 0, 0));
+
+ // Add all
+ add(imgLabel, BorderLayout.WEST);
+ add(mainPanel, BorderLayout.CENTER);
+
+ return null;
+ }
+
+ }.setVisible(true);
+ }
+ });
+ }
+ }
+ });
+
+ return delete;
+ }
+
/**
* Create the open menu item for a book or a source (no LUID).
*
selectedBook.getMeta().getLuid());
MetaData source = selectedBook.getMeta().clone();
source.setLuid(null);
- GuiReaderBook.clearIcon(source);
+ GuiReaderCoverImager.clearIcon(source);
}
}
});
@Override
public void run() {
try {
- reader.read(book.getMeta().getLuid(), pg);
+ reader.read(book.getMeta().getLuid(), false, pg);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {