step 2
[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 70 private boolean cached;
c349fd48 71 private boolean seeWordCount;
10d558d2 72
4d205683 73 /**
5dd985cf 74 * Create a new {@link GuiReaderBook} item for the given {@link Story}.
4d205683 75 *
e42573a0
NR
76 * @param reader
77 * the associated reader
79a99506
NR
78 * @param info
79 * the information about the story to represent
4d205683
NR
80 * @param cached
81 * TRUE if it is locally cached
5dd985cf 82 * @param seeWordCount
793f1071 83 * TRUE to see word counts, FALSE to see authors
4d205683 84 */
79a99506 85 public GuiReaderBook(Reader reader, GuiReaderBookInfo info, boolean cached,
e42573a0 86 boolean seeWordCount) {
79a99506 87 this.info = info;
c349fd48
NR
88 this.cached = cached;
89 this.seeWordCount = seeWordCount;
4d205683 90
df6e2d88 91 icon = new JLabel(GuiReaderCoverImager.generateCoverIcon(
79a99506 92 reader.getLibrary(), info));
c349fd48
NR
93
94 title = new JLabel();
95 updateTitle();
b4dc6ab5 96
edd46289
NR
97 setLayout(new BorderLayout(10, 10));
98 add(icon, BorderLayout.CENTER);
99 add(title, BorderLayout.SOUTH);
333f0e7b
NR
100
101 setupListeners();
333f0e7b
NR
102 }
103
104 /**
105 * The book current selection state.
106 *
4d205683 107 * @return the selection state
333f0e7b
NR
108 */
109 public boolean isSelected() {
110 return selected;
111 }
112
113 /**
114 * The book current selection state.
17fafa56
NR
115 * <p>
116 * Setting this value to true can cause a "select" action to occur if the
117 * previous state was "unselected".
333f0e7b
NR
118 *
119 * @param selected
4d205683 120 * TRUE if it is selected
333f0e7b
NR
121 */
122 public void setSelected(boolean selected) {
edd46289
NR
123 if (this.selected != selected) {
124 this.selected = selected;
125 repaint();
17fafa56
NR
126
127 if (selected) {
128 select();
129 }
edd46289 130 }
333f0e7b
NR
131 }
132
df6e2d88
NR
133 /**
134 * The item mouse-hover state.
135 *
136 * @return TRUE if it is mouse-hovered
137 */
138 private boolean isHovered() {
139 return this.hovered;
140 }
141
4d205683
NR
142 /**
143 * The item mouse-hover state.
144 *
145 * @param hovered
146 * TRUE if it is mouse-hovered
147 */
333f0e7b 148 private void setHovered(boolean hovered) {
edd46289
NR
149 if (this.hovered != hovered) {
150 this.hovered = hovered;
151 repaint();
152 }
333f0e7b
NR
153 }
154
4d205683
NR
155 /**
156 * Setup the mouse listener that will activate {@link BookActionListener}
157 * events.
158 */
333f0e7b 159 private void setupListeners() {
5dd985cf 160 listeners = new ArrayList<GuiReaderBook.BookActionListener>();
333f0e7b 161 addMouseListener(new MouseListener() {
211f7ddb 162 @Override
333f0e7b 163 public void mouseReleased(MouseEvent e) {
e20686b4 164 if (isEnabled() && e.isPopupTrigger()) {
9843a5e5
NR
165 popup(e);
166 }
333f0e7b
NR
167 }
168
211f7ddb 169 @Override
333f0e7b 170 public void mousePressed(MouseEvent e) {
e20686b4 171 if (isEnabled() && e.isPopupTrigger()) {
9843a5e5
NR
172 popup(e);
173 }
333f0e7b
NR
174 }
175
211f7ddb 176 @Override
333f0e7b
NR
177 public void mouseExited(MouseEvent e) {
178 setHovered(false);
179 }
180
211f7ddb 181 @Override
333f0e7b
NR
182 public void mouseEntered(MouseEvent e) {
183 setHovered(true);
184 }
185
211f7ddb 186 @Override
333f0e7b 187 public void mouseClicked(MouseEvent e) {
3b2b638f
NR
188 if (isEnabled()) {
189 Date now = new Date();
190 if (lastClick != null
191 && now.getTime() - lastClick.getTime() < doubleClickDelay) {
192 click(true);
193 } else {
194 click(false);
195 }
9843a5e5 196
3b2b638f 197 lastClick = now;
e20686b4 198 e.consume();
333f0e7b 199 }
333f0e7b 200 }
333f0e7b 201
9843a5e5 202 private void click(boolean doubleClick) {
17fafa56
NR
203 if (doubleClick) {
204 action();
205 } else {
206 select();
9843a5e5 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 214 }
e20686b4
NR
215
216 e.consume();
9843a5e5
NR
217 }
218 });
333f0e7b
NR
219 }
220
4d205683
NR
221 /**
222 * Add a new {@link BookActionListener} on this item.
223 *
224 * @param listener
225 * the listener
226 */
92fb0719 227 public void addActionListener(BookActionListener listener) {
333f0e7b
NR
228 listeners.add(listener);
229 }
d3c84ac3 230
17fafa56
NR
231 /**
232 * Cause an action to occur on this {@link GuiReaderBook}.
233 */
234 public void action() {
235 for (BookActionListener listener : listeners) {
236 listener.action(GuiReaderBook.this);
237 }
238 }
239
240 /**
241 * Cause a select event on this {@link GuiReaderBook}.
242 */
243 private void select() {
244 for (BookActionListener listener : listeners) {
245 listener.select(GuiReaderBook.this);
246 }
247 }
248
4d205683 249 /**
79a99506 250 * The information about the book represented by this item.
4d205683 251 *
22848428 252 * @return the meta
4d205683 253 */
79a99506
NR
254 public GuiReaderBookInfo getInfo() {
255 return info;
10d558d2
NR
256 }
257
258 /**
5dd985cf 259 * This item {@link GuiReader} library cache state.
10d558d2 260 *
5dd985cf 261 * @return TRUE if it is present in the {@link GuiReader} cache
10d558d2
NR
262 */
263 public boolean isCached() {
264 return cached;
265 }
266
267 /**
5dd985cf 268 * This item {@link GuiReader} library cache state.
10d558d2
NR
269 *
270 * @param cached
5dd985cf 271 * TRUE if it is present in the {@link GuiReader} cache
10d558d2
NR
272 */
273 public void setCached(boolean cached) {
f977d05b
NR
274 if (this.cached != cached) {
275 this.cached = cached;
edd46289 276 repaint();
f977d05b 277 }
10d558d2
NR
278 }
279
4d205683 280 /**
c349fd48
NR
281 * Update the title, paint the item, then call
282 * {@link GuiReaderCoverImager#paintOverlay(Graphics, boolean, boolean, boolean, boolean)}
283 * .
4d205683 284 */
d3c84ac3
NR
285 @Override
286 public void paint(Graphics g) {
c349fd48 287 updateTitle();
d3c84ac3 288 super.paint(g);
df6e2d88
NR
289 GuiReaderCoverImager.paintOverlay(g, isEnabled(), isSelected(),
290 isHovered(), isCached());
085a2f9a 291 }
c349fd48
NR
292
293 /**
294 * Update the title with the currently registered information.
295 */
296 private void updateTitle() {
297 String optSecondary = info.getSecondaryInfo(seeWordCount);
298 title.setText(String
299 .format("<html>"
300 + "<body style='width: %d px; height: %d px; text-align: center'>"
301 + "%s" + "<br>" + "<span style='color: %s;'>" + "%s"
302 + "</span>" + "</body>" + "</html>",
303 GuiReaderCoverImager.TEXT_WIDTH,
304 GuiReaderCoverImager.TEXT_HEIGHT, info.getMainInfo(),
305 AUTHOR_COLOR, optSecondary));
306 }
333f0e7b 307}