1 package be
.nikiroo
.fanfix_swing
.gui
;
3 import java
.awt
.BorderLayout
;
4 import java
.awt
.Component
;
5 import java
.awt
.Dimension
;
8 import java
.awt
.event
.ActionEvent
;
9 import java
.awt
.event
.ActionListener
;
10 import java
.awt
.event
.MouseAdapter
;
11 import java
.awt
.event
.MouseEvent
;
12 import java
.util
.ArrayList
;
13 import java
.util
.HashMap
;
14 import java
.util
.List
;
16 import java
.util
.concurrent
.ExecutionException
;
18 import javax
.swing
.DefaultListModel
;
19 import javax
.swing
.JList
;
20 import javax
.swing
.JPopupMenu
;
21 import javax
.swing
.ListCellRenderer
;
22 import javax
.swing
.ListSelectionModel
;
23 import javax
.swing
.SwingWorker
;
25 import be
.nikiroo
.fanfix
.Instance
;
26 import be
.nikiroo
.fanfix
.data
.MetaData
;
27 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
28 import be
.nikiroo
.fanfix_swing
.Actions
;
29 import be
.nikiroo
.fanfix_swing
.gui
.book
.BookBlock
;
30 import be
.nikiroo
.fanfix_swing
.gui
.book
.BookInfo
;
31 import be
.nikiroo
.fanfix_swing
.gui
.book
.BookLine
;
32 import be
.nikiroo
.fanfix_swing
.gui
.book
.BookPopup
;
33 import be
.nikiroo
.fanfix_swing
.gui
.utils
.DelayWorker
;
34 import be
.nikiroo
.fanfix_swing
.gui
.utils
.ListenerPanel
;
35 import be
.nikiroo
.fanfix_swing
.gui
.utils
.UiHelper
;
37 public class BooksPanel
extends ListenerPanel
{
38 private class ListModel
extends DefaultListModel
<BookInfo
> {
39 public void fireElementChanged(BookInfo element
) {
40 int index
= indexOf(element
);
42 fireContentsChanged(element
, index
, index
);
47 static public final String INVALIDATE_CACHE
= "invalidate_cache";
49 private List
<BookInfo
> bookInfos
= new ArrayList
<BookInfo
>();
50 private Map
<BookInfo
, BookLine
> books
= new HashMap
<BookInfo
, BookLine
>();
51 private boolean seeWordCount
;
52 private boolean listMode
;
54 private JList
<BookInfo
> list
;
55 private int hoveredIndex
= -1;
56 private ListModel data
= new ListModel();
57 private DelayWorker bookCoverUpdater
;
59 private SearchBar searchBar
;
61 public BooksPanel(boolean listMode
) {
62 setLayout(new BorderLayout());
64 searchBar
= new SearchBar();
65 add(searchBar
, BorderLayout
.NORTH
);
67 searchBar
.addActionListener(new ActionListener() {
69 public void actionPerformed(ActionEvent e
) {
70 filter(searchBar
.getText());
74 bookCoverUpdater
= new DelayWorker(20);
75 bookCoverUpdater
.start();
76 add(UiHelper
.scroll(initList(listMode
)), BorderLayout
.CENTER
);
79 // null or empty -> all sources
80 // sources hierarchy supported ("source/" will includes all "source" and
82 public void load(final List
<String
> sources
, final List
<String
> authors
,
83 final List
<String
> tags
) {
84 new SwingWorker
<List
<BookInfo
>, Void
>() {
86 protected List
<BookInfo
> doInBackground() throws Exception
{
87 List
<BookInfo
> bookInfos
= new ArrayList
<BookInfo
>();
88 BasicLibrary lib
= Instance
.getInstance().getLibrary();
89 for (MetaData meta
: lib
.getList().filter(sources
, authors
,
91 bookInfos
.add(BookInfo
.fromMeta(lib
, meta
));
98 protected void done() {
101 } catch (InterruptedException e
) {
103 } catch (ExecutionException e
) {
111 public void load(List
<BookInfo
> bookInfos
) {
112 this.bookInfos
.clear();
113 this.bookInfos
.addAll(bookInfos
);
114 bookCoverUpdater
.clear();
116 filter(searchBar
.getText());
120 private void filter(String filter
) {
122 for (BookInfo bookInfo
: bookInfos
) {
123 if (bookInfo
.getMainInfo() == null || filter
.isEmpty()
124 || bookInfo
.getMainInfo().toLowerCase()
125 .contains(filter
.toLowerCase())) {
126 data
.addElement(bookInfo
);
133 * The secondary value content: word count or author.
135 * @return TRUE to see word counts, FALSE to see authors
137 public boolean isSeeWordCount() {
142 * The secondary value content: word count or author.
144 * @param seeWordCount
145 * TRUE to see word counts, FALSE to see authors
147 public void setSeeWordCount(boolean seeWordCount
) {
148 if (this.seeWordCount
!= seeWordCount
) {
150 for (BookLine book
: books
.values()) {
151 book
.setSeeWordCount(seeWordCount
);
159 private JList
<BookInfo
> initList(boolean listMode
) {
160 final JList
<BookInfo
> list
= new JList
<BookInfo
>(data
);
162 final JPopupMenu popup
= new BookPopup(
163 Instance
.getInstance().getLibrary(), new BookPopup
.Informer() {
165 public void setCached(BookInfo book
, boolean cached
) {
166 book
.setCached(cached
);
167 fireElementChanged(book
);
170 public void fireElementChanged(BookInfo book
) {
171 data
.fireElementChanged(book
);
175 public List
<BookInfo
> getSelected() {
176 List
<BookInfo
> selected
= new ArrayList
<BookInfo
>();
177 for (int index
: list
.getSelectedIndices()) {
178 selected
.add(data
.get(index
));
185 public BookInfo
getUniqueSelected() {
186 List
<BookInfo
> selected
= getSelected();
187 if (selected
.size() == 1) {
188 return selected
.get(0);
194 public void invalidateCache() {
195 // TODO: also reset the popup menu for sources/author
196 fireActionPerformed(INVALIDATE_CACHE
);
200 list
.addMouseMotionListener(new MouseAdapter() {
202 public void mouseMoved(MouseEvent me
) {
203 if (popup
.isShowing())
206 Point p
= new Point(me
.getX(), me
.getY());
207 int index
= list
.locationToIndex(p
);
208 if (index
!= hoveredIndex
) {
209 hoveredIndex
= index
;
214 list
.addMouseListener(new MouseAdapter() {
216 public void mousePressed(MouseEvent e
) {
221 public void mouseReleased(MouseEvent e
) {
226 public void mouseExited(MouseEvent e
) {
227 if (popup
.isShowing())
230 if (hoveredIndex
> -1) {
237 public void mouseClicked(MouseEvent e
) {
238 super.mouseClicked(e
);
239 if (e
.getClickCount() == 2) {
240 int index
= list
.locationToIndex(e
.getPoint());
241 list
.setSelectedIndex(index
);
243 final BookInfo book
= data
.get(index
);
244 BasicLibrary lib
= Instance
.getInstance().getLibrary();
246 Actions
.openExternal(lib
, book
.getMeta(), BooksPanel
.this,
250 book
.setCached(true);
251 data
.fireElementChanged(book
);
257 private void check(MouseEvent e
) {
258 if (e
.isPopupTrigger()) {
259 if (list
.getSelectedIndices().length
<= 1) {
260 list
.setSelectedIndex(
261 list
.locationToIndex(e
.getPoint()));
264 popup
.show(list
, e
.getX(), e
.getY());
269 list
.setSelectionMode(ListSelectionModel
.MULTIPLE_INTERVAL_SELECTION
);
270 list
.setSelectedIndex(0);
271 list
.setCellRenderer(generateRenderer());
272 list
.setVisibleRowCount(0);
275 setListMode(listMode
);
279 private ListCellRenderer
<BookInfo
> generateRenderer() {
280 return new ListCellRenderer
<BookInfo
>() {
282 public Component
getListCellRendererComponent(
283 JList
<?
extends BookInfo
> list
, BookInfo value
, int index
,
284 boolean isSelected
, boolean cellHasFocus
) {
285 BookLine book
= books
.get(value
);
288 book
= new BookLine(value
, seeWordCount
);
290 book
= new BookBlock(value
, seeWordCount
);
291 startUpdateBookCover((BookBlock
) book
);
293 books
.put(value
, book
);
296 book
.setSelected(isSelected
);
297 book
.setHovered(index
== hoveredIndex
);
303 private void startUpdateBookCover(final BookBlock book
) {
304 bookCoverUpdater
.delay(book
.getInfo().getId(),
305 new SwingWorker
<Image
, Void
>() {
307 protected Image
doInBackground() throws Exception
{
308 BasicLibrary lib
= Instance
.getInstance().getLibrary();
309 return BookBlock
.generateCoverImage(lib
,
313 protected void done() {
315 book
.setCoverImage(get());
316 data
.fireElementChanged(book
.getInfo());
317 } catch (Exception e
) {
318 // TODO ? probably just log
324 public boolean isListMode() {
328 public void setListMode(boolean listMode
) {
329 this.listMode
= listMode
;
331 list
.setLayoutOrientation(
332 listMode ? JList
.VERTICAL
: JList
.HORIZONTAL_WRAP
);
334 StringBuilder longString
= new StringBuilder();
335 for (int i
= 0; i
< 20; i
++) {
337 "Some long string, which is 50 chars long itself...");
340 bookCoverUpdater
.clear();
341 Dimension sz
= new BookLine(
342 BookInfo
.fromSource(null, longString
.toString()), true)
344 list
.setFixedCellHeight((int) sz
.getHeight());
345 list
.setFixedCellWidth(list
.getWidth());
347 Dimension sz
= new BookBlock(
348 BookInfo
.fromSource(null, longString
.toString()), true)
350 list
.setFixedCellHeight((int) sz
.getHeight());
351 list
.setFixedCellWidth((int) sz
.getWidth());