X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Freader%2Fui%2FGuiReaderGroup.java;h=cc3f1e15f59794e4c3117b3f9efe3e9d1be90ecd;hb=1387a30ab59dbf4071f2c5e5e0e08ca98c75b726;hp=78e1d06a473bc91b8cafcff9147bd3f2325d85ed;hpb=07e0fc1e184a10bb85866b20527e28f6329e64b3;p=nikiroo-utils.git diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java index 78e1d06..cc3f1e1 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderGroup.java @@ -2,12 +2,16 @@ package be.nikiroo.fanfix.reader.ui; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; 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; @@ -27,10 +31,13 @@ public class GuiReaderGroup extends JPanel { private static final long serialVersionUID = 1L; private BookActionListener action; private Color backgroundColor; + private Color backgroundColorDef; + private Color backgroundColorDefPane; private GuiReader reader; private List infos; private List books; private JPanel pane; + private JLabel titleLabel; private boolean words; // words or authors (secondary info on books) private int itemsPerLine; @@ -41,37 +48,34 @@ public class GuiReaderGroup extends JPanel { * the {@link GuiReaderBook} used to probe some information about * the stories * @param title - * the title of this group + * the title of this group (can be NULL for "no title", an empty + * {@link String} will trigger a default title for empty groups) * @param backgroundColor * the background colour to use (or NULL for default) */ public GuiReaderGroup(GuiReader reader, String title, Color backgroundColor) { this.reader = reader; - this.backgroundColor = backgroundColor; this.pane = new JPanel(); - pane.setLayout(new WrapLayout(WrapLayout.LEADING, 5, 5)); - if (backgroundColor != null) { - pane.setBackground(backgroundColor); - setBackground(backgroundColor); - } + + this.backgroundColorDef = getBackground(); + this.backgroundColorDefPane = pane.getBackground(); + setBackground(backgroundColor); setLayout(new BorderLayout(0, 10)); - add(pane, BorderLayout.CENTER); - if (title != null) { - if (title.isEmpty()) { - title = GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN); - } + // Make it focusable: + setFocusable(true); + setEnabled(true); + setVisible(true); - JLabel label = new JLabel(); - label.setText(String.format("" - + "
" - + "%s" + "" + "", title)); - label.setHorizontalAlignment(JLabel.CENTER); - add(label, BorderLayout.NORTH); - } + add(pane, BorderLayout.CENTER); + + titleLabel = new JLabel(); + titleLabel.setHorizontalAlignment(JLabel.CENTER); + add(titleLabel, BorderLayout.NORTH); + setTitle(title); // Compute the number of items per line at each resize addComponentListener(new ComponentAdapter() { @@ -84,11 +88,92 @@ public class GuiReaderGroup extends JPanel { 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); + } + }); + } + + /** + * Note: this class supports NULL as a background colour, which will revert + * it to its default state. + *

+ * Note: this class' implementation will also set the main pane background + * colour at the same time. + *

+ * Sets the background colour of this component. The background colour is + * used only if the component is opaque, and only by subclasses of + * JComponent or ComponentUI implementations. + * Direct subclasses of JComponent must override + * paintComponent to honour this property. + *

+ * It is up to the look and feel to honour this property, some may choose to + * ignore it. + * + * @param backgroundColor + * the desired background Colour + * @see java.awt.Component#getBackground + * @see #setOpaque + * + * @beaninfo preferred: true bound: true attribute: visualUpdate true + * description: The background colour of the component. + */ + @Override + public void setBackground(Color backgroundColor) { + this.backgroundColor = backgroundColor; + + Color cme = backgroundColor == null ? backgroundColorDef + : backgroundColor; + Color cpane = backgroundColor == null ? backgroundColorDefPane + : backgroundColor; + + if (pane != null) { // can happen at theme setup time + pane.setBackground(cpane); + } + super.setBackground(cme); + } + + /** + * The title of this group (can be NULL for "no title", an empty + * {@link String} will trigger a default title for empty groups) + * + * @param title + * the title or NULL + */ + public void setTitle(String title) { + if (title != null) { + if (title.isEmpty()) { + title = GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN); + } + + titleLabel.setText(String.format("" + + "
" + + "%s" + "" + "", title)); + titleLabel.setVisible(true); + } else { + titleLabel.setVisible(false); + } } /** @@ -96,8 +181,13 @@ public class GuiReaderGroup extends JPanel { * up/down one line at a time. */ private void computeItemsPerLine() { - // TODO - itemsPerLine = 5; + itemsPerLine = 1; + + if (books != null && books.size() > 0) { + // this.pane holds all the books with a hgap of 5 px + int wbook = books.get(0).getWidth() + 5; + itemsPerLine = pane.getWidth() / wbook; + } } /** @@ -109,6 +199,30 @@ public class GuiReaderGroup extends JPanel { */ public void setActionListener(BookActionListener action) { this.action = action; + refreshBooks(); + } + + /** + * Clear all the books in this {@link GuiReaderGroup}. + */ + public void clear() { + refreshBooks(new ArrayList()); + } + + /** + * Refresh the list of {@link GuiReaderBook}s displayed in the control. + */ + public void refreshBooks() { + refreshBooks(infos, words); + } + + /** + * Refresh the list of {@link GuiReaderBook}s displayed in the control. + * + * @param infos + * the new list of infos + */ + public void refreshBooks(List infos) { refreshBooks(infos, words); } @@ -144,7 +258,7 @@ public class GuiReaderGroup extends JPanel { if (infos != null) { for (GuiReaderBookInfo info : infos) { boolean isCached = false; - if (info.getMeta() != null) { + if (info.getMeta() != null && info.getMeta().getLuid() != null) { isCached = reader.isCached(info.getMeta().getLuid()); } @@ -159,13 +273,15 @@ 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); } } @Override - public void popupRequested(GuiReaderBook book, MouseEvent e) { + public void popupRequested(GuiReaderBook book, + Component target, int x, int y) { } @Override @@ -185,6 +301,8 @@ public class GuiReaderGroup extends JPanel { pane.repaint(); validate(); repaint(); + + computeItemsPerLine(); } /** @@ -212,6 +330,66 @@ public class GuiReaderGroup extends JPanel { repaint(); } + /** + * The number of books in this group. + * + * @return the count + */ + public int getBooksCount() { + return books.size(); + } + + /** + * Return the index of the currently selected book if any, -1 if none. + * + * @return the index or -1 + */ + public 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>) + * @param forceRange + * TRUE to constraint the index to the first/last element, FALSE + * to unselect when outside the range + */ + public 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.isEmpty()) { + books.get(index).setSelected(true); + } + } + /** * The action to execute when a key is typed. * @@ -220,7 +398,35 @@ public class GuiReaderGroup extends JPanel { */ private void onKeyTyped(KeyEvent e) { boolean consumed = false; - System.out.println(e); + boolean action = e.getKeyChar() == '\n'; + boolean popup = e.getKeyChar() == ' '; + if (action || popup) { + consumed = true; + + int index = getSelectedBookIndex(); + if (index >= 0) { + GuiReaderBook book = books.get(index); + if (action) { + book.action(); + } else if (popup) { + book.popup(book, book.getWidth() / 2, book.getHeight() / 2); + } + } + } + + 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()) { @@ -231,44 +437,40 @@ public class GuiReaderGroup extends JPanel { offset = 1; break; case KeyEvent.VK_UP: - offset = itemsPerLine; + offset = -itemsPerLine; break; case KeyEvent.VK_DOWN: - offset = -itemsPerLine; + offset = itemsPerLine; break; } if (offset != 0) { consumed = true; - int selected = -1; - for (int i = 0; i < books.size(); i++) { - if (books.get(i).isSelected()) { - selected = i; - break; - } - } - - if (selected >= 0) { - int newSelect = selected + offset; - if (newSelect >= books.size()) { - newSelect = books.size() - 1; - } - - if (selected != newSelect && newSelect >= 0) { - if (selected >= 0) { - books.get(selected).setSelected(false); - books.get(newSelect).setSelected(true); - } - } + int previousIndex = getSelectedBookIndex(); + if (previousIndex >= 0) { + setSelectedBook(previousIndex + offset, true); } } } if (consumed) { e.consume(); - } else { - super.processKeyEvent(e); + } + } + + @Override + public void paint(Graphics g) { + super.paint(g); + + Rectangle clip = g.getClipBounds(); + if (clip.getWidth() <= 0 || clip.getHeight() <= 0) { + return; + } + + if (!isEnabled()) { + g.setColor(new Color(128, 128, 128, 128)); + g.fillRect(clip.x, clip.y, clip.width, clip.height); } } }