keyboard: step 1
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderGroup.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.ui;
4310bae9
NR
2
3import java.awt.BorderLayout;
4import java.awt.Color;
5import java.awt.event.ActionListener;
07e0fc1e
NR
6import java.awt.event.ComponentAdapter;
7import java.awt.event.ComponentEvent;
8import java.awt.event.KeyAdapter;
9import java.awt.event.KeyEvent;
4310bae9
NR
10import java.awt.event.MouseEvent;
11import java.util.ArrayList;
12import java.util.List;
13
14import javax.swing.JLabel;
15import javax.swing.JPanel;
16
5bc9573b 17import be.nikiroo.fanfix.bundles.StringIdGui;
16a81ef7 18import be.nikiroo.fanfix.reader.ui.GuiReaderBook.BookActionListener;
4310bae9
NR
19import be.nikiroo.utils.ui.WrapLayout;
20
21/**
5dd985cf 22 * A group of {@link GuiReaderBook}s for display.
4310bae9
NR
23 *
24 * @author niki
25 */
5dd985cf 26public class GuiReaderGroup extends JPanel {
4310bae9
NR
27 private static final long serialVersionUID = 1L;
28 private BookActionListener action;
29 private Color backgroundColor;
5dd985cf 30 private GuiReader reader;
79a99506 31 private List<GuiReaderBookInfo> infos;
5dd985cf 32 private List<GuiReaderBook> books;
4310bae9 33 private JPanel pane;
793f1071 34 private boolean words; // words or authors (secondary info on books)
07e0fc1e 35 private int itemsPerLine;
4310bae9
NR
36
37 /**
5dd985cf 38 * Create a new {@link GuiReaderGroup}.
4310bae9
NR
39 *
40 * @param reader
e42573a0
NR
41 * the {@link GuiReaderBook} used to probe some information about
42 * the stories
4310bae9
NR
43 * @param title
44 * the title of this group
45 * @param backgroundColor
46 * the background colour to use (or NULL for default)
47 */
e42573a0 48 public GuiReaderGroup(GuiReader reader, String title, Color backgroundColor) {
4310bae9
NR
49 this.reader = reader;
50 this.backgroundColor = backgroundColor;
51
52 this.pane = new JPanel();
53
54 pane.setLayout(new WrapLayout(WrapLayout.LEADING, 5, 5));
55 if (backgroundColor != null) {
56 pane.setBackground(backgroundColor);
57 setBackground(backgroundColor);
58 }
59
60 setLayout(new BorderLayout(0, 10));
61 add(pane, BorderLayout.CENTER);
62
63 if (title != null) {
64 if (title.isEmpty()) {
5bc9573b 65 title = GuiReader.trans(StringIdGui.MENU_AUTHORS_UNKNOWN);
4310bae9
NR
66 }
67
68 JLabel label = new JLabel();
69 label.setText(String.format("<html>"
71d72f34
NR
70 + "<body style='text-align: center; color: gray;'><br><b>"
71 + "%s" + "</b></body>" + "</html>", title));
4310bae9
NR
72 label.setHorizontalAlignment(JLabel.CENTER);
73 add(label, BorderLayout.NORTH);
74 }
07e0fc1e
NR
75
76 // Compute the number of items per line at each resize
77 addComponentListener(new ComponentAdapter() {
78 @Override
79 public void componentResized(ComponentEvent e) {
80 super.componentResized(e);
81 computeItemsPerLine();
82 }
83 });
84 computeItemsPerLine();
85
86 addKeyListener(new KeyAdapter() {
87 @Override
88 public void keyTyped(KeyEvent e) {
89 onKeyTyped(e);
90 }
91 });
92 }
93
94 /**
95 * Compute how many items can fit in a line so UP and DOWN can be used to go
96 * up/down one line at a time.
97 */
98 private void computeItemsPerLine() {
99 // TODO
100 itemsPerLine = 5;
4310bae9
NR
101 }
102
103 /**
104 * Set the {@link ActionListener} that will be fired on each
5dd985cf 105 * {@link GuiReaderBook} action.
4310bae9
NR
106 *
107 * @param action
108 * the action
109 */
110 public void setActionListener(BookActionListener action) {
111 this.action = action;
79a99506 112 refreshBooks(infos, words);
4310bae9
NR
113 }
114
115 /**
5dd985cf 116 * Refresh the list of {@link GuiReaderBook}s displayed in the control.
4310bae9 117 *
c349fd48
NR
118 * @param infos
119 * the new list of infos
793f1071
NR
120 * @param seeWordcount
121 * TRUE to see word counts, FALSE to see authors
4310bae9 122 */
fb1ffdd0
NR
123 public void refreshBooks(List<GuiReaderBookInfo> infos, boolean seeWordcount) {
124 this.infos = infos;
8590da19
NR
125 refreshBooks(seeWordcount);
126 }
127
128 /**
129 * Refresh the list of {@link GuiReaderBook}s displayed in the control.
130 * <p>
131 * Will not change the current stories.
132 *
133 * @param seeWordcount
134 * TRUE to see word counts, FALSE to see authors
135 */
136 public void refreshBooks(boolean seeWordcount) {
793f1071 137 this.words = seeWordcount;
4310bae9 138
5dd985cf 139 books = new ArrayList<GuiReaderBook>();
4310bae9
NR
140 invalidate();
141 pane.invalidate();
142 pane.removeAll();
143
fb1ffdd0
NR
144 if (infos != null) {
145 for (GuiReaderBookInfo info : infos) {
79a99506
NR
146 boolean isCached = false;
147 if (info.getMeta() != null) {
148 isCached = reader.isCached(info.getMeta().getLuid());
149 }
150
151 GuiReaderBook book = new GuiReaderBook(reader, info, isCached,
fb1ffdd0 152 words);
4310bae9
NR
153 if (backgroundColor != null) {
154 book.setBackground(backgroundColor);
155 }
156
157 books.add(book);
158
159 book.addActionListener(new BookActionListener() {
211f7ddb 160 @Override
5dd985cf
NR
161 public void select(GuiReaderBook book) {
162 for (GuiReaderBook abook : books) {
4310bae9
NR
163 abook.setSelected(abook == book);
164 }
165 }
166
211f7ddb 167 @Override
e42573a0 168 public void popupRequested(GuiReaderBook book, MouseEvent e) {
4310bae9
NR
169 }
170
211f7ddb 171 @Override
5dd985cf 172 public void action(GuiReaderBook book) {
4310bae9
NR
173 }
174 });
175
176 if (action != null) {
177 book.addActionListener(action);
178 }
179
180 pane.add(book);
181 }
182 }
183
184 pane.validate();
185 pane.repaint();
186 validate();
187 repaint();
188 }
189
190 /**
191 * Enables or disables this component, depending on the value of the
192 * parameter <code>b</code>. An enabled component can respond to user input
193 * and generate events. Components are enabled initially by default.
194 * <p>
195 * Disabling this component will also affect its children.
196 *
197 * @param b
198 * If <code>true</code>, this component is enabled; otherwise
199 * this component is disabled
200 */
201 @Override
202 public void setEnabled(boolean b) {
203 if (books != null) {
5dd985cf 204 for (GuiReaderBook book : books) {
4310bae9
NR
205 book.setEnabled(b);
206 book.repaint();
207 }
208 }
209
210 pane.setEnabled(b);
211 super.setEnabled(b);
212 repaint();
213 }
07e0fc1e
NR
214
215 /**
216 * The action to execute when a key is typed.
217 *
218 * @param e
219 * the key event
220 */
221 private void onKeyTyped(KeyEvent e) {
222 boolean consumed = false;
223 System.out.println(e);
224 if (e.isActionKey()) {
225 int offset = 0;
226 switch (e.getKeyCode()) {
227 case KeyEvent.VK_LEFT:
228 offset = -1;
229 break;
230 case KeyEvent.VK_RIGHT:
231 offset = 1;
232 break;
233 case KeyEvent.VK_UP:
234 offset = itemsPerLine;
235 break;
236 case KeyEvent.VK_DOWN:
237 offset = -itemsPerLine;
238 break;
239 }
240
241 if (offset != 0) {
242 consumed = true;
243
244 int selected = -1;
245 for (int i = 0; i < books.size(); i++) {
246 if (books.get(i).isSelected()) {
247 selected = i;
248 break;
249 }
250 }
251
252 if (selected >= 0) {
253 int newSelect = selected + offset;
254 if (newSelect >= books.size()) {
255 newSelect = books.size() - 1;
256 }
257
258 if (selected != newSelect && newSelect >= 0) {
259 if (selected >= 0) {
260 books.get(selected).setSelected(false);
261 books.get(newSelect).setSelected(true);
262 }
263 }
264 }
265 }
266 }
267
268 if (consumed) {
269 e.consume();
270 } else {
271 super.processKeyEvent(e);
272 }
273 }
4310bae9 274}