import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Queue;
import java.util.concurrent.ExecutionException;
import javax.swing.DefaultListModel;
import javax.swing.JPopupMenu;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
-import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import be.nikiroo.fanfix.Instance;
import be.nikiroo.fanfix_swing.gui.book.BookInfo;
import be.nikiroo.fanfix_swing.gui.book.BookLine;
import be.nikiroo.fanfix_swing.gui.book.BookPopup;
+import be.nikiroo.fanfix_swing.gui.utils.DelayWorker;
import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel;
import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
private JList<BookInfo> list;
private int hoveredIndex = -1;
private ListModel data = new ListModel();
+ private DelayWorker bookCoverUpdater;
private SearchBar searchBar;
- private Queue<BookBlock> updateBookQueue = new LinkedList<BookBlock>();
- private Object updateBookQueueLock = new Object();
-
public BooksPanel(boolean listMode) {
setLayout(new BorderLayout());
}
});
+ bookCoverUpdater = new DelayWorker(20);
+ bookCoverUpdater.start();
add(UiHelper.scroll(initList(listMode)), BorderLayout.CENTER);
-
- Thread bookBlocksUpdater = new Thread(new Runnable() {
- @Override
- public void run() {
- while (true) {
- BasicLibrary lib = Instance.getInstance().getLibrary();
- while (true) {
- final BookBlock book;
- synchronized (updateBookQueueLock) {
- if (!updateBookQueue.isEmpty()) {
- book = updateBookQueue.remove();
- } else {
- book = null;
- break;
- }
- }
-
- try {
- final Image coverImage = BookBlock
- .generateCoverImage(lib, book.getInfo());
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- try {
- book.setCoverImage(coverImage);
- data.fireElementChanged(book.getInfo());
- } catch (Exception e) {
- }
- }
- });
- } catch (Exception e) {
- }
- }
-
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- }
- }
- }
- });
- bookBlocksUpdater.setName("BookBlocks visual updater");
- bookBlocksUpdater.setDaemon(true);
- bookBlocksUpdater.start();
}
// null or empty -> all sources
public void load(List<BookInfo> bookInfos) {
this.bookInfos.clear();
this.bookInfos.addAll(bookInfos);
- synchronized (updateBookQueueLock) {
- updateBookQueue.clear();
- }
+ bookCoverUpdater.clear();
filter(searchBar.getText());
}
book = new BookLine(value, seeWordCount);
} else {
book = new BookBlock(value, seeWordCount);
- synchronized (updateBookQueueLock) {
- updateBookQueue.add((BookBlock) book);
- }
+ startUpdateBookCover((BookBlock) book);
}
books.put(value, book);
}
};
}
+ private void startUpdateBookCover(final BookBlock book) {
+ bookCoverUpdater.delay(book.getInfo().getId(),
+ new SwingWorker<Image, Void>() {
+ @Override
+ protected Image doInBackground() throws Exception {
+ BasicLibrary lib = Instance.getInstance().getLibrary();
+ return BookBlock.generateCoverImage(lib,
+ book.getInfo());
+ }
+
+ protected void done() {
+ try {
+ book.setCoverImage(get());
+ data.fireElementChanged(book.getInfo());
+ } catch (Exception e) {
+ // TODO ? probably just log
+ }
+ }
+ });
+ }
+
public boolean isListMode() {
return listMode;
}
listMode ? JList.VERTICAL : JList.HORIZONTAL_WRAP);
if (listMode) {
- synchronized (updateBookQueueLock) {
- updateBookQueue.clear();
- }
+ bookCoverUpdater.clear();
}
}
}
import javax.imageio.ImageIO;
import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.fanfix.library.BasicLibrary;
import be.nikiroo.fanfix.reader.ui.GuiReaderBookInfo;
import be.nikiroo.utils.Image;
UIUtils.drawEllipse3D(g, UNCACHED_ICON_COLOR, COVER_WIDTH + HOFFSET + 30, 10, 20, 20, cached);
}
- /**
- * Generate a cover icon based upon the given {@link MetaData}.
- *
- * @param lib the library the meta comes from
- * @param meta the {@link MetaData}
- *
- * @return the image
- */
- static public java.awt.Image generateCoverImage(BasicLibrary lib, MetaData meta) {
- return generateCoverImage(lib, BookInfo.fromMeta(lib, meta));
- }
-
/**
* The width of a cover image.
*
Graphics2D g = resizedImage.createGraphics();
try {
- g.setColor(Color.white);
- g.fillRect(0, HOFFSET, COVER_WIDTH, COVER_HEIGHT);
-
- if (cover != null) {
- BufferedImage coverb = ImageUtilsAwt.fromImage(cover);
- g.drawImage(coverb, 0, HOFFSET, COVER_WIDTH, COVER_HEIGHT, null);
- } else {
- g.setColor(Color.black);
- g.drawLine(0, HOFFSET, COVER_WIDTH, HOFFSET + COVER_HEIGHT);
- g.drawLine(COVER_WIDTH, HOFFSET, 0, HOFFSET + COVER_HEIGHT);
+ if (info != null && info.supportsCover()) {
+ g.setColor(Color.white);
+ g.fillRect(0, HOFFSET, COVER_WIDTH, COVER_HEIGHT);
+
+ if (cover != null) {
+ BufferedImage coverb = ImageUtilsAwt.fromImage(cover);
+ g.drawImage(coverb, 0, HOFFSET, COVER_WIDTH, COVER_HEIGHT, null);
+ } else {
+ g.setColor(Color.black);
+ g.drawLine(0, HOFFSET, COVER_WIDTH, HOFFSET + COVER_HEIGHT);
+ g.drawLine(COVER_WIDTH, HOFFSET, 0, HOFFSET + COVER_HEIGHT);
+ }
}
} finally {
g.dispose();
return null;
}
+
+ /**
+ * This {@link BookInfo} could have a cover (so we need to somehow represent
+ * that to the user).
+ *
+ * @return TRUE if it does
+ */
+ public boolean supportsCover() {
+ return type != Type.TAG;
+ }
/**
* Create a new book describing the given {@link Story}.
--- /dev/null
+package be.nikiroo.fanfix_swing.gui.utils;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.SwingWorker;
+
+@SuppressWarnings("rawtypes")
+public class DelayWorker {
+ private Map<String, SwingWorker> lazyEnCours;
+ private Object lazyEnCoursLock;
+
+ private Object waiter;
+
+ private boolean cont;
+ private boolean paused;
+ private Thread loop;
+
+ public DelayWorker(final int delayMs) {
+ lazyEnCours = new HashMap<String, SwingWorker>();
+ lazyEnCoursLock = new Object();
+ waiter = new Object();
+ cont = true;
+ paused = false;
+
+ loop = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while (cont) {
+ try {
+ Thread.sleep(delayMs);
+ } catch (InterruptedException e) {
+ }
+
+ List<SwingWorker> workers;
+ synchronized (lazyEnCoursLock) {
+ workers = new LinkedList<SwingWorker>(
+ lazyEnCours.values());
+ lazyEnCours.clear();
+ }
+ for (SwingWorker worker : workers) {
+ worker.execute();
+ }
+
+ synchronized (waiter) {
+ do {
+ try {
+ if (cont)
+ waiter.wait();
+ } catch (InterruptedException e) {
+ }
+ } while (cont && paused);
+ }
+ }
+ }
+ });
+ loop.setDaemon(true);
+ loop.setName("Loop for DelayWorker");
+ }
+
+ // twice = not legal
+ public void start() {
+ loop.start();
+ }
+
+ public void pause() {
+ paused = true;
+ }
+
+ public boolean isPaused() {
+ return paused;
+ }
+
+ public void resume() {
+ synchronized (waiter) {
+ paused = false;
+ wakeup();
+ }
+ }
+
+ public void stop() {
+ synchronized (waiter) {
+ cont = false;
+ wakeup();
+ }
+ }
+
+ public void clear() {
+ synchronized (lazyEnCoursLock) {
+ lazyEnCours.clear();
+ }
+ }
+
+ public <T, V> void delay(final String id, final SwingWorker<T, V> worker) {
+ synchronized (lazyEnCoursLock) {
+ lazyEnCours.put(id, worker);
+ }
+
+ wakeup();
+ }
+
+ private void wakeup() {
+ synchronized (waiter) {
+ waiter.notifyAll();
+ }
+ }
+}