X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Freader%2Fui%2FGuiReaderGroup.java;h=db21c49c8c0d9414c4be0d6e3b1d4f41c043ed52;hb=17fafa56087ec04ff386c6e56d38c51c98d71511;hp=c96b02df266e0ef307a023600a6085dd2caa83ad;hpb=16a81ef7656c5c692fb831927e75edde25dd77a0;p=fanfix.git diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java index c96b02d..db21c49 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java @@ -3,15 +3,20 @@ package be.nikiroo.fanfix.reader.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; -import javax.management.RuntimeErrorException; import javax.swing.JLabel; import javax.swing.JPanel; -import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.fanfix.bundles.StringIdGui; import be.nikiroo.fanfix.reader.ui.GuiReaderBook.BookActionListener; import be.nikiroo.utils.ui.WrapLayout; @@ -25,10 +30,11 @@ public class GuiReaderGroup extends JPanel { private BookActionListener action; private Color backgroundColor; private GuiReader reader; - private List stories; + private List infos; private List books; private JPanel pane; private boolean words; // words or authors (secondary info on books) + private int itemsPerLine; /** * Create a new {@link GuiReaderGroup}. @@ -54,11 +60,17 @@ public class GuiReaderGroup extends JPanel { } setLayout(new BorderLayout(0, 10)); + + // Make it focusable: + setFocusable(true); + setEnabled(true); + setVisible(true); + add(pane, BorderLayout.CENTER); if (title != null) { if (title.isEmpty()) { - title = "[unknown]"; + title = GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN); } JLabel label = new JLabel(); @@ -68,6 +80,52 @@ public class GuiReaderGroup extends JPanel { label.setHorizontalAlignment(JLabel.CENTER); add(label, BorderLayout.NORTH); } + + // Compute the number of items per line at each resize + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + super.componentResized(e); + computeItemsPerLine(); + } + }); + computeItemsPerLine(); + + addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + onKeyPressed(e); + } + + @Override + public void keyTyped(KeyEvent e) { + onKeyTyped(e); + } + }); + + addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (getSelectedBookIndex() < 0) { + setSelectedBook(0, true); + } + } + + @Override + public void focusLost(FocusEvent e) { + setBackground(null); + setSelectedBook(-1, false); + } + }); + } + + /** + * Compute how many items can fit in a line so UP and DOWN can be used to go + * up/down one line at a time. + */ + private void computeItemsPerLine() { + // TODO + itemsPerLine = 5; } /** @@ -79,19 +137,31 @@ public class GuiReaderGroup extends JPanel { */ public void setActionListener(BookActionListener action) { this.action = action; - refreshBooks(stories, words); + refreshBooks(infos, words); } /** * Refresh the list of {@link GuiReaderBook}s displayed in the control. * - * @param stories - * the stories + * @param infos + * the new list of infos * @param seeWordcount * TRUE to see word counts, FALSE to see authors */ - public void refreshBooks(List stories, boolean seeWordcount) { - this.stories = stories; + public void refreshBooks(List infos, boolean seeWordcount) { + this.infos = infos; + refreshBooks(seeWordcount); + } + + /** + * Refresh the list of {@link GuiReaderBook}s displayed in the control. + *

+ * Will not change the current stories. + * + * @param seeWordcount + * TRUE to see word counts, FALSE to see authors + */ + public void refreshBooks(boolean seeWordcount) { this.words = seeWordcount; books = new ArrayList(); @@ -99,10 +169,15 @@ public class GuiReaderGroup extends JPanel { pane.invalidate(); pane.removeAll(); - if (stories != null) { - for (MetaData meta : stories) { - GuiReaderBook book = new GuiReaderBook(reader, meta, - reader.isCached(meta.getLuid()), seeWordcount); + if (infos != null) { + for (GuiReaderBookInfo info : infos) { + boolean isCached = false; + if (info.getMeta() != null) { + isCached = reader.isCached(info.getMeta().getLuid()); + } + + GuiReaderBook book = new GuiReaderBook(reader, info, isCached, + words); if (backgroundColor != null) { book.setBackground(backgroundColor); } @@ -112,6 +187,7 @@ public class GuiReaderGroup extends JPanel { book.addActionListener(new BookActionListener() { @Override public void select(GuiReaderBook book) { + GuiReaderGroup.this.requestFocusInWindow(); for (GuiReaderBook abook : books) { abook.setSelected(abook == book); } @@ -164,4 +240,117 @@ public class GuiReaderGroup extends JPanel { super.setEnabled(b); repaint(); } + + /** + * Return the index of the currently selected book if any, -1 if none. + * + * @return the index or -1 + */ + private int getSelectedBookIndex() { + int index = -1; + for (int i = 0; i < books.size(); i++) { + if (books.get(i).isSelected()) { + index = i; + break; + } + } + return index; + } + + /** + * Select the given book, or unselect all items. + * + * @param index + * the index of the book to select, can be outside the bounds + * (either all the items will be unselected or the first or last + * book will then be selected, see forceRange>/tt>) + * @param forceRange + * TRUE to constraint the index to the first/last element, FALSE + * to unselect when outside the range + */ + private void setSelectedBook(int index, boolean forceRange) { + int previousIndex = getSelectedBookIndex(); + + if (index >= books.size()) { + if (forceRange) { + index = books.size() - 1; + } else { + index = -1; + } + } + + if (index < 0 && forceRange) { + index = 0; + } + + if (previousIndex >= 0) { + books.get(previousIndex).setSelected(false); + } + + if (index >= 0) { + books.get(index).setSelected(true); + } + } + + /** + * The action to execute when a key is typed. + * + * @param e + * the key event + */ + private void onKeyTyped(KeyEvent e) { + boolean consumed = false; + if (e.getKeyChar() == '\n') { + consumed = true; + + int index = getSelectedBookIndex(); + if (index >= 0) { + books.get(index).action(); + } + } + + if (consumed) { + e.consume(); + } + } + + /** + * The action to execute when a key is pressed. + * + * @param e + * the key event + */ + private void onKeyPressed(KeyEvent e) { + boolean consumed = false; + if (e.isActionKey()) { + int offset = 0; + switch (e.getKeyCode()) { + case KeyEvent.VK_LEFT: + offset = -1; + break; + case KeyEvent.VK_RIGHT: + offset = 1; + break; + case KeyEvent.VK_UP: + offset = -itemsPerLine; + break; + case KeyEvent.VK_DOWN: + offset = itemsPerLine; + break; + } + + if (offset != 0) { + consumed = true; + + int previousIndex = getSelectedBookIndex(); + if (previousIndex >= 0) { + setSelectedBook(previousIndex + offset, true); + } + } + } + + if (consumed) { + e.consume(); + } + } }