From bdded4b57be305fc04a98860b3da8c89b662a9be Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Thu, 9 Apr 2020 16:48:54 +0200 Subject: [PATCH] working on ui refresh for books --- .../nikiroo/fanfix_swing/gui/BooksPanel.java | 87 +++++--------- .../gui/book/BookCoverImager.java | 35 ++---- .../fanfix_swing/gui/book/BookInfo.java | 10 ++ .../fanfix_swing/gui/utils/DelayWorker.java | 109 ++++++++++++++++++ 4 files changed, 159 insertions(+), 82 deletions(-) create mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java diff --git a/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java b/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java index 810323f..3a07afb 100644 --- a/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java +++ b/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java @@ -10,10 +10,8 @@ import java.awt.event.MouseAdapter; 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; @@ -21,7 +19,6 @@ import javax.swing.JList; 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; @@ -32,6 +29,7 @@ import be.nikiroo.fanfix_swing.gui.book.BookBlock; 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; @@ -55,12 +53,10 @@ public class BooksPanel extends ListenerPanel { private JList list; private int hoveredIndex = -1; private ListModel data = new ListModel(); + private DelayWorker bookCoverUpdater; private SearchBar searchBar; - private Queue updateBookQueue = new LinkedList(); - private Object updateBookQueueLock = new Object(); - public BooksPanel(boolean listMode) { setLayout(new BorderLayout()); @@ -74,51 +70,9 @@ public class BooksPanel extends ListenerPanel { } }); + 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 @@ -156,9 +110,7 @@ public class BooksPanel extends ListenerPanel { public void load(List bookInfos) { this.bookInfos.clear(); this.bookInfos.addAll(bookInfos); - synchronized (updateBookQueueLock) { - updateBookQueue.clear(); - } + bookCoverUpdater.clear(); filter(searchBar.getText()); } @@ -335,9 +287,7 @@ public class BooksPanel extends ListenerPanel { book = new BookLine(value, seeWordCount); } else { book = new BookBlock(value, seeWordCount); - synchronized (updateBookQueueLock) { - updateBookQueue.add((BookBlock) book); - } + startUpdateBookCover((BookBlock) book); } books.put(value, book); } @@ -349,6 +299,27 @@ public class BooksPanel extends ListenerPanel { }; } + private void startUpdateBookCover(final BookBlock book) { + bookCoverUpdater.delay(book.getInfo().getId(), + new SwingWorker() { + @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; } @@ -360,9 +331,7 @@ public class BooksPanel extends ListenerPanel { listMode ? JList.VERTICAL : JList.HORIZONTAL_WRAP); if (listMode) { - synchronized (updateBookQueueLock) { - updateBookQueue.clear(); - } + bookCoverUpdater.clear(); } } } diff --git a/src/be/nikiroo/fanfix_swing/gui/book/BookCoverImager.java b/src/be/nikiroo/fanfix_swing/gui/book/BookCoverImager.java index 8bdcfab..95e0aab 100644 --- a/src/be/nikiroo/fanfix_swing/gui/book/BookCoverImager.java +++ b/src/be/nikiroo/fanfix_swing/gui/book/BookCoverImager.java @@ -15,7 +15,6 @@ import java.net.MalformedURLException; 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; @@ -110,18 +109,6 @@ class BookCoverImager { 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. * @@ -174,16 +161,18 @@ class BookCoverImager { 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(); diff --git a/src/be/nikiroo/fanfix_swing/gui/book/BookInfo.java b/src/be/nikiroo/fanfix_swing/gui/book/BookInfo.java index 6859cfa..72aee90 100644 --- a/src/be/nikiroo/fanfix_swing/gui/book/BookInfo.java +++ b/src/be/nikiroo/fanfix_swing/gui/book/BookInfo.java @@ -186,6 +186,16 @@ public class BookInfo { 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}. diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java b/src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java new file mode 100644 index 0000000..19a9b5c --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/utils/DelayWorker.java @@ -0,0 +1,109 @@ +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 lazyEnCours; + private Object lazyEnCoursLock; + + private Object waiter; + + private boolean cont; + private boolean paused; + private Thread loop; + + public DelayWorker(final int delayMs) { + lazyEnCours = new HashMap(); + 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 workers; + synchronized (lazyEnCoursLock) { + workers = new LinkedList( + 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 void delay(final String id, final SwingWorker worker) { + synchronized (lazyEnCoursLock) { + lazyEnCours.put(id, worker); + } + + wakeup(); + } + + private void wakeup() { + synchronized (waiter) { + waiter.notifyAll(); + } + } +} -- 2.27.0