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