gui: add support for author cover
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderBook.java
CommitLineData
16a81ef7 1package be.nikiroo.fanfix.reader.ui;
333f0e7b
NR
2
3import java.awt.BorderLayout;
d3c84ac3 4import java.awt.Graphics;
333f0e7b
NR
5import java.awt.event.MouseEvent;
6import java.awt.event.MouseListener;
333f0e7b
NR
7import java.util.ArrayList;
8import java.util.Date;
9import java.util.EventListener;
10import java.util.List;
11
333f0e7b
NR
12import javax.swing.JLabel;
13import javax.swing.JPanel;
14
4d205683 15import be.nikiroo.fanfix.data.Story;
16a81ef7 16import be.nikiroo.fanfix.reader.Reader;
333f0e7b
NR
17
18/**
5dd985cf 19 * A book item presented in a {@link GuiReaderFrame}.
333f0e7b
NR
20 *
21 * @author niki
22 */
5dd985cf 23class GuiReaderBook extends JPanel {
333f0e7b
NR
24 /**
25 * Action on a book item.
26 *
27 * @author niki
28 */
92fb0719 29 interface BookActionListener extends EventListener {
333f0e7b
NR
30 /**
31 * The book was selected (single click).
32 *
33 * @param book
5dd985cf 34 * the {@link GuiReaderBook} itself
333f0e7b 35 */
5dd985cf 36 public void select(GuiReaderBook book);
333f0e7b
NR
37
38 /**
39 * The book was double-clicked.
40 *
41 * @param book
5dd985cf 42 * the {@link GuiReaderBook} itself
333f0e7b 43 */
5dd985cf 44 public void action(GuiReaderBook book);
9843a5e5
NR
45
46 /**
5dd985cf 47 * A popup menu was requested for this {@link GuiReaderBook}.
9843a5e5
NR
48 *
49 * @param book
5dd985cf 50 * the {@link GuiReaderBook} itself
9843a5e5
NR
51 * @param e
52 * the {@link MouseEvent} that generated this call
53 */
5dd985cf 54 public void popupRequested(GuiReaderBook book, MouseEvent e);
333f0e7b
NR
55 }
56
4d205683
NR
57 private static final long serialVersionUID = 1L;
58
b4dc6ab5 59 private static final String AUTHOR_COLOR = "#888888";
4d205683 60 private static final long doubleClickDelay = 200; // in ms
3b2b638f 61
333f0e7b 62 private JLabel icon;
3b2b638f 63 private JLabel title;
333f0e7b
NR
64 private boolean selected;
65 private boolean hovered;
66 private Date lastClick;
4d205683 67
92fb0719 68 private List<BookActionListener> listeners;
79a99506 69 private GuiReaderBookInfo info;
10d558d2
NR
70 private boolean cached;
71
4d205683 72 /**
5dd985cf 73 * Create a new {@link GuiReaderBook} item for the given {@link Story}.
4d205683 74 *
e42573a0
NR
75 * @param reader
76 * the associated reader
79a99506
NR
77 * @param info
78 * the information about the story to represent
4d205683
NR
79 * @param cached
80 * TRUE if it is locally cached
5dd985cf 81 * @param seeWordCount
793f1071 82 * TRUE to see word counts, FALSE to see authors
4d205683 83 */
79a99506 84 public GuiReaderBook(Reader reader, GuiReaderBookInfo info, boolean cached,
e42573a0 85 boolean seeWordCount) {
10d558d2 86 this.cached = cached;
79a99506 87 this.info = info;
793f1071 88
79a99506 89 String optSecondary = info.getSecondaryInfo(seeWordCount);
4d205683 90
df6e2d88 91 icon = new JLabel(GuiReaderCoverImager.generateCoverIcon(
79a99506 92 reader.getLibrary(), info));
3b2b638f 93 title = new JLabel(
b4dc6ab5
NR
94 String.format(
95 "<html>"
96 + "<body style='width: %d px; height: %d px; text-align: center'>"
97 + "%s" + "<br>" + "<span style='color: %s;'>"
98 + "%s" + "</span>" + "</body>" + "</html>",
df6e2d88 99 GuiReaderCoverImager.TEXT_WIDTH,
79a99506 100 GuiReaderCoverImager.TEXT_HEIGHT, info.getMainInfo(),
df6e2d88 101 AUTHOR_COLOR, optSecondary));
b4dc6ab5 102
edd46289
NR
103 setLayout(new BorderLayout(10, 10));
104 add(icon, BorderLayout.CENTER);
105 add(title, BorderLayout.SOUTH);
333f0e7b
NR
106
107 setupListeners();
333f0e7b
NR
108 }
109
110 /**
111 * The book current selection state.
112 *
4d205683 113 * @return the selection state
333f0e7b
NR
114 */
115 public boolean isSelected() {
116 return selected;
117 }
118
119 /**
120 * The book current selection state.
121 *
122 * @param selected
4d205683 123 * TRUE if it is selected
333f0e7b
NR
124 */
125 public void setSelected(boolean selected) {
edd46289
NR
126 if (this.selected != selected) {
127 this.selected = selected;
128 repaint();
129 }
333f0e7b
NR
130 }
131
df6e2d88
NR
132 /**
133 * The item mouse-hover state.
134 *
135 * @return TRUE if it is mouse-hovered
136 */
137 private boolean isHovered() {
138 return this.hovered;
139 }
140
4d205683
NR
141 /**
142 * The item mouse-hover state.
143 *
144 * @param hovered
145 * TRUE if it is mouse-hovered
146 */
333f0e7b 147 private void setHovered(boolean hovered) {
edd46289
NR
148 if (this.hovered != hovered) {
149 this.hovered = hovered;
150 repaint();
151 }
333f0e7b
NR
152 }
153
4d205683
NR
154 /**
155 * Setup the mouse listener that will activate {@link BookActionListener}
156 * events.
157 */
333f0e7b 158 private void setupListeners() {
5dd985cf 159 listeners = new ArrayList<GuiReaderBook.BookActionListener>();
333f0e7b 160 addMouseListener(new MouseListener() {
211f7ddb 161 @Override
333f0e7b 162 public void mouseReleased(MouseEvent e) {
9843a5e5
NR
163 if (e.isPopupTrigger()) {
164 popup(e);
165 }
333f0e7b
NR
166 }
167
211f7ddb 168 @Override
333f0e7b 169 public void mousePressed(MouseEvent e) {
9843a5e5
NR
170 if (e.isPopupTrigger()) {
171 popup(e);
172 }
333f0e7b
NR
173 }
174
211f7ddb 175 @Override
333f0e7b
NR
176 public void mouseExited(MouseEvent e) {
177 setHovered(false);
178 }
179
211f7ddb 180 @Override
333f0e7b
NR
181 public void mouseEntered(MouseEvent e) {
182 setHovered(true);
183 }
184
211f7ddb 185 @Override
333f0e7b 186 public void mouseClicked(MouseEvent e) {
3b2b638f
NR
187 if (isEnabled()) {
188 Date now = new Date();
189 if (lastClick != null
190 && now.getTime() - lastClick.getTime() < doubleClickDelay) {
191 click(true);
192 } else {
193 click(false);
194 }
9843a5e5 195
3b2b638f 196 lastClick = now;
333f0e7b 197 }
333f0e7b 198 }
333f0e7b 199
9843a5e5
NR
200 private void click(boolean doubleClick) {
201 for (BookActionListener listener : listeners) {
202 if (doubleClick) {
5dd985cf 203 listener.action(GuiReaderBook.this);
9843a5e5 204 } else {
5dd985cf 205 listener.select(GuiReaderBook.this);
9843a5e5
NR
206 }
207 }
333f0e7b 208 }
9843a5e5
NR
209
210 private void popup(MouseEvent e) {
211 for (BookActionListener listener : listeners) {
5dd985cf
NR
212 listener.select((GuiReaderBook.this));
213 listener.popupRequested(GuiReaderBook.this, e);
9843a5e5
NR
214 }
215 }
216 });
333f0e7b
NR
217 }
218
4d205683
NR
219 /**
220 * Add a new {@link BookActionListener} on this item.
221 *
222 * @param listener
223 * the listener
224 */
92fb0719 225 public void addActionListener(BookActionListener listener) {
333f0e7b
NR
226 listeners.add(listener);
227 }
d3c84ac3 228
4d205683 229 /**
79a99506 230 * The information about the book represented by this item.
4d205683 231 *
22848428 232 * @return the meta
4d205683 233 */
79a99506
NR
234 public GuiReaderBookInfo getInfo() {
235 return info;
10d558d2
NR
236 }
237
238 /**
5dd985cf 239 * This item {@link GuiReader} library cache state.
10d558d2 240 *
5dd985cf 241 * @return TRUE if it is present in the {@link GuiReader} cache
10d558d2
NR
242 */
243 public boolean isCached() {
244 return cached;
245 }
246
247 /**
5dd985cf 248 * This item {@link GuiReader} library cache state.
10d558d2
NR
249 *
250 * @param cached
5dd985cf 251 * TRUE if it is present in the {@link GuiReader} cache
10d558d2
NR
252 */
253 public void setCached(boolean cached) {
f977d05b
NR
254 if (this.cached != cached) {
255 this.cached = cached;
edd46289 256 repaint();
f977d05b 257 }
10d558d2
NR
258 }
259
4d205683 260 /**
5dd985cf 261 * Paint the item, then call {@link GuiReaderBook#paintOverlay(Graphics)}.
4d205683 262 */
d3c84ac3
NR
263 @Override
264 public void paint(Graphics g) {
265 super.paint(g);
df6e2d88
NR
266 GuiReaderCoverImager.paintOverlay(g, isEnabled(), isSelected(),
267 isHovered(), isCached());
085a2f9a 268 }
333f0e7b 269}