Commit | Line | Data |
---|---|---|
16a81ef7 | 1 | package be.nikiroo.fanfix.reader.ui; |
4310bae9 NR |
2 | |
3 | import java.awt.BorderLayout; | |
4 | import java.awt.Color; | |
5 | import java.awt.event.ActionListener; | |
07e0fc1e NR |
6 | import java.awt.event.ComponentAdapter; |
7 | import java.awt.event.ComponentEvent; | |
8 | import java.awt.event.KeyAdapter; | |
9 | import java.awt.event.KeyEvent; | |
4310bae9 NR |
10 | import java.awt.event.MouseEvent; |
11 | import java.util.ArrayList; | |
12 | import java.util.List; | |
13 | ||
14 | import javax.swing.JLabel; | |
15 | import javax.swing.JPanel; | |
16 | ||
5bc9573b | 17 | import be.nikiroo.fanfix.bundles.StringIdGui; |
16a81ef7 | 18 | import be.nikiroo.fanfix.reader.ui.GuiReaderBook.BookActionListener; |
4310bae9 NR |
19 | import 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 | 26 | public 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 | } |