properties dialog
authorNiki Roo <niki@nikiroo.be>
Sat, 18 Apr 2020 22:39:32 +0000 (00:39 +0200)
committerNiki Roo <niki@nikiroo.be>
Sat, 18 Apr 2020 22:39:32 +0000 (00:39 +0200)
src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java [new file with mode: 0644]
src/be/nikiroo/fanfix_swing/gui/PropertiesPane.java [new file with mode: 0644]
src/be/nikiroo/fanfix_swing/gui/book/BookBlock.java
src/be/nikiroo/fanfix_swing/gui/book/BookCoverImager.java
src/be/nikiroo/fanfix_swing/gui/book/BookLine.java
src/be/nikiroo/fanfix_swing/gui/book/BookPopup.java
src/be/nikiroo/fanfix_swing/gui/importer/ImporterItem.java
src/be/nikiroo/fanfix_swing/gui/utils/CoverImager.java [new file with mode: 0644]

diff --git a/src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java b/src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java
new file mode 100644 (file)
index 0000000..db0654b
--- /dev/null
@@ -0,0 +1,40 @@
+package be.nikiroo.fanfix_swing.gui;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JFrame;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.bundles.StringIdGui;
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.library.BasicLibrary;
+
+/**
+ * A frame displaying properties and other information of a {@link Story}.
+ * 
+ * @author niki
+ */
+public class PropertiesFrame extends JFrame {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * Create a new {@link PropertiesFrame}.
+        * 
+        * @param lib
+        *            the library to use for the cover image
+        * @param meta
+        *            the meta to describe
+        */
+       public PropertiesFrame(BasicLibrary lib, MetaData meta) {
+               setTitle(Instance.getInstance().getTransGui().getString(
+                               StringIdGui.TITLE_STORY, meta.getLuid(), meta.getTitle()));
+
+               PropertiesPane desc = new PropertiesPane(lib, meta);
+               setSize(800, (int) desc.getPreferredSize().getHeight()
+                               + 2 * desc.getBorderThickness());
+
+               setLayout(new BorderLayout());
+               add(desc, BorderLayout.NORTH);
+       }
+}
diff --git a/src/be/nikiroo/fanfix_swing/gui/PropertiesPane.java b/src/be/nikiroo/fanfix_swing/gui/PropertiesPane.java
new file mode 100644 (file)
index 0000000..b701fe6
--- /dev/null
@@ -0,0 +1,102 @@
+package be.nikiroo.fanfix_swing.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+
+import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.data.Story;
+import be.nikiroo.fanfix.library.BasicLibrary;
+import be.nikiroo.fanfix.reader.BasicReader;
+import be.nikiroo.fanfix_swing.gui.book.BookInfo;
+import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
+
+/**
+ * A panel displaying properties and other information of a {@link Story}.
+ * 
+ * @author niki
+ */
+public class PropertiesPane extends JPanel {
+       private static final long serialVersionUID = 1L;
+       private final int space = 10;
+
+       /**
+        * Create a new {@link PropertiesPane}.
+        * 
+        * @param lib
+        *            the library to use for the cover image
+        * @param meta
+        *            the meta to describe
+        */
+       public PropertiesPane(BasicLibrary lib, MetaData meta) {
+               // Image
+               ImageIcon img = new ImageIcon(CoverImager.generateCoverImage(lib,
+                               BookInfo.fromMeta(lib, meta)));
+
+               setLayout(new BorderLayout());
+
+               // Main panel
+               JPanel mainPanel = new JPanel(new BorderLayout());
+               JPanel mainPanelKeys = new JPanel();
+               mainPanelKeys.setLayout(new BoxLayout(mainPanelKeys, BoxLayout.Y_AXIS));
+               JPanel mainPanelValues = new JPanel();
+               mainPanelValues
+                               .setLayout(new BoxLayout(mainPanelValues, BoxLayout.Y_AXIS));
+
+               mainPanel.add(mainPanelKeys, BorderLayout.WEST);
+               mainPanel.add(mainPanelValues, BorderLayout.CENTER);
+
+               Map<String, String> desc = BasicReader.getMetaDesc(meta);
+
+               Color trans = new Color(0, 0, 0, 1);
+               Color base = mainPanelValues.getBackground();
+               for (String key : desc.keySet()) {
+                       JTextArea jKey = new JTextArea(key);
+                       jKey.setFont(new Font(jKey.getFont().getFontName(), Font.BOLD,
+                                       jKey.getFont().getSize()));
+                       jKey.setEditable(false);
+                       jKey.setLineWrap(false);
+                       jKey.setBackground(trans);
+                       mainPanelKeys.add(jKey);
+
+                       final JTextArea jValue = new JTextArea(desc.get(key));
+                       jValue.setEditable(false);
+                       jValue.setLineWrap(false);
+                       jValue.setBackground(base);
+                       mainPanelValues.add(jValue);
+               }
+
+               // Image
+               JLabel imgLabel = new JLabel(img);
+               imgLabel.setVerticalAlignment(JLabel.TOP);
+
+               // Borders
+               mainPanelKeys.setBorder(
+                               BorderFactory.createEmptyBorder(space, space, space, space));
+               mainPanelValues.setBorder(
+                               BorderFactory.createEmptyBorder(space, space, space, space));
+               imgLabel.setBorder(BorderFactory.createEmptyBorder(0, space, space, 0));
+
+               // Add all
+               add(imgLabel, BorderLayout.WEST);
+               add(mainPanel, BorderLayout.CENTER);
+       }
+
+       /**
+        * The invisible border size (multiply by 2 if you need the total width or
+        * the total height).
+        * 
+        * @return the invisible border thickness
+        */
+       public int getBorderThickness() {
+               return space;
+       }
+}
index 329c714e200c8f3b04aac2b2736a5e9b76867c0c..183bd5768dd16df0d03ae43c3ff911051ac712a9 100644 (file)
@@ -11,6 +11,7 @@ import javax.swing.JPanel;
 import be.nikiroo.fanfix.data.Story;
 import be.nikiroo.fanfix.library.BasicLibrary;
 import be.nikiroo.fanfix_swing.gui.BooksPanel;
+import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
 
 /**
  * A book item presented in a {@link BooksPanel}.
@@ -21,7 +22,7 @@ import be.nikiroo.fanfix_swing.gui.BooksPanel;
  */
 public class BookBlock extends BookLine {
        static private final long serialVersionUID = 1L;
-       static private Image empty = BookCoverImager.generateCoverImage(null,
+       static private Image empty = CoverImager.generateCoverImage(null,
                        (BookInfo) null);
 
        private JLabel title;
@@ -46,8 +47,8 @@ public class BookBlock extends BookLine {
                updateMeta();
 
                JPanel filler = new JPanel();
-               filler.setPreferredSize(new Dimension(BookCoverImager.getCoverWidth(),
-                               BookCoverImager.getCoverHeight()));
+               filler.setPreferredSize(new Dimension(CoverImager.getCoverWidth(),
+                               CoverImager.getCoverHeight()));
                filler.setOpaque(false);
 
                setLayout(new BorderLayout(10, 10));
@@ -88,7 +89,7 @@ public class BookBlock extends BookLine {
                                + "</body>" + "</html>", BookCoverImager.TEXT_WIDTH,
                                BookCoverImager.TEXT_HEIGHT, main, color, optSecondary));
 
-               setBackground(BookCoverImager.getBackground(isEnabled(), isSelected(),
+               setBackground(CoverImager.getBackground(isEnabled(), isSelected(),
                                isHovered()));
        }
 
@@ -104,6 +105,6 @@ public class BookBlock extends BookLine {
         */
        static public java.awt.Image generateCoverImage(BasicLibrary lib,
                        BookInfo info) {
-               return BookCoverImager.generateCoverImage(lib, info);
+               return CoverImager.generateCoverImage(lib, info);
        }
 }
index 2b0795f617042e8766a611022ad9dafea802b5fe..ca166d579dce705d56d478af1611937af04ac792 100644 (file)
@@ -2,22 +2,10 @@ package be.nikiroo.fanfix_swing.gui.book;
 
 import java.awt.Color;
 import java.awt.Graphics;
-import java.awt.Graphics2D;
 import java.awt.Polygon;
 import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
 
-import javax.imageio.ImageIO;
-
-import be.nikiroo.fanfix.Instance;
-import be.nikiroo.fanfix.library.BasicLibrary;
-import be.nikiroo.utils.Image;
-import be.nikiroo.utils.ui.ImageUtilsAwt;
+import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
 import be.nikiroo.utils.ui.UIUtils;
 
 /**
@@ -43,23 +31,6 @@ class BookCoverImager {
        public static final int TEXT_HEIGHT = 50;
        public static final int TEXT_WIDTH = COVER_WIDTH + 40;
 
-       //
-
-       static public Color getBackground(boolean enabled, boolean selected,
-                       boolean hovered) {
-               Color color = new Color(255, 255, 255, 0);
-               if (!enabled) {
-               } else if (selected && !hovered) {
-                       color = new Color(80, 80, 100, 40);
-               } else if (!selected && hovered) {
-                       color = new Color(230, 230, 255, 100);
-               } else if (selected && hovered) {
-                       color = new Color(200, 200, 255, 100);
-               }
-
-               return color;
-       }
-
        /**
         * Draw a partially transparent overlay if needed depending upon the
         * selection and mouse-hover states on top of the normal component, as well
@@ -111,7 +82,7 @@ class BookCoverImager {
                g.setColor(SPINE_COLOR_RIGHT);
                g.fillPolygon(new Polygon(xs, ys, xs.length));
 
-               Color color = getBackground(enabled, selected, hovered);
+               Color color = CoverImager.getBackground(enabled, selected, hovered);
 
                g.setColor(color);
                g.fillRect(clip.x, clip.y, clip.width, clip.height);
@@ -119,126 +90,4 @@ class BookCoverImager {
                UIUtils.drawEllipse3D(g, UNCACHED_ICON_COLOR,
                                COVER_WIDTH + HOFFSET + 30, 10, 20, 20, cached);
        }
-
-       /**
-        * The width of a cover image.
-        * 
-        * @return the width
-        */
-       static public int getCoverWidth() {
-               return SPINE_WIDTH + COVER_WIDTH;
-       }
-
-       /**
-        * The height of a cover image.
-        * 
-        * @return the height
-        */
-       static public int getCoverHeight() {
-               return COVER_HEIGHT + HOFFSET;
-       }
-
-       /**
-        * Generate a cover icon based upon the given {@link GuiReaderBookInfo}.
-        * 
-        * @param lib
-        *            the library the meta comes from (can be NULL)
-        * @param info
-        *            the {@link GuiReaderBookInfo}
-        * 
-        * @return the image
-        */
-       static public java.awt.Image generateCoverImage(BasicLibrary lib,
-                       BookInfo info) {
-               BufferedImage resizedImage = null;
-               String id = getIconId(info);
-
-               InputStream in = Instance.getInstance().getCache().getFromCache(id);
-               if (in != null) {
-                       try {
-                               resizedImage = ImageUtilsAwt.fromImage(new Image(in));
-                               in.close();
-                               in = null;
-                       } catch (IOException e) {
-                               Instance.getInstance().getTraceHandler().error(e);
-                       }
-               }
-
-               if (resizedImage == null) {
-                       try {
-                               Image cover = null;
-                               if (info != null) {
-                                       cover = info.getBaseImage(lib);
-                               }
-
-                               resizedImage = new BufferedImage(getCoverWidth(),
-                                               getCoverHeight(), BufferedImage.TYPE_4BYTE_ABGR);
-
-                               Graphics2D g = resizedImage.createGraphics();
-                               try {
-                                       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();
-                               }
-
-                               // Only save image with a cover, not the X thing
-                               if (id != null && cover != null) {
-                                       ByteArrayOutputStream out = new ByteArrayOutputStream();
-                                       ImageIO.write(resizedImage, "png", out);
-                                       byte[] imageBytes = out.toByteArray();
-                                       in = new ByteArrayInputStream(imageBytes);
-                                       Instance.getInstance().getCache().addToCache(in, id);
-                                       in.close();
-                                       in = null;
-                               }
-                       } catch (MalformedURLException e) {
-                               Instance.getInstance().getTraceHandler().error(e);
-                       } catch (IOException e) {
-                               Instance.getInstance().getTraceHandler().error(e);
-                       }
-               }
-
-               return resizedImage;
-       }
-
-       /**
-        * Manually clear the icon set for this item.
-        * 
-        * @param info
-        *            the info about the story or source/type or author
-        */
-       static public void clearIcon(BookInfo info) {
-               String id = getIconId(info);
-               Instance.getInstance().getCache().removeFromCache(id);
-       }
-
-       /**
-        * Get a unique ID from this {@link GuiReaderBookInfo} (note that it can be
-        * a story, a fake item for a source/type or a fake item for an author).
-        * 
-        * @param info
-        *            the info or NULL for a generic (non unique!) ID
-        * @return the unique ID
-        */
-       static private String getIconId(BookInfo info) {
-               return (info == null ? "" : info.getId() + ".") + "book-thumb_"
-                               + SPINE_WIDTH + "x" + COVER_WIDTH + "+" + SPINE_HEIGHT + "+"
-                               + COVER_HEIGHT + "@" + HOFFSET;
-       }
 }
index 4e2e3f4c6b641902b869ff736f14b3c34dfba569..984a5b944bf495c1d347b24eb8fdd4228d5f31d7 100644 (file)
@@ -10,6 +10,7 @@ import javax.swing.SwingConstants;
 
 import be.nikiroo.fanfix.data.Story;
 import be.nikiroo.fanfix_swing.gui.BooksPanel;
+import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
 
 /**
  * A book item presented in a {@link BooksPanel}.
@@ -204,7 +205,7 @@ public class BookLine extends JPanel {
                title.setText(main);
                secondary.setText(optSecondary + " ");
 
-               setBackground(BookCoverImager.getBackground(isEnabled(), isSelected(),
+               setBackground(CoverImager.getBackground(isEnabled(), isSelected(),
                                isHovered()));
 
                remove(iconCached);
index 991f44197dafa24f4fe941e138b922bc5adbac56..3d874cc1b99f394835882fafe14bf037a95bb36e 100644 (file)
@@ -30,6 +30,8 @@ import be.nikiroo.fanfix.library.BasicLibrary;
 import be.nikiroo.fanfix.library.BasicLibrary.Status;
 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
 import be.nikiroo.fanfix_swing.Actions;
+import be.nikiroo.fanfix_swing.gui.PropertiesFrame;
+import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
 import be.nikiroo.fanfix_swing.gui.utils.UiHelper;
 import be.nikiroo.utils.Progress;
 import be.nikiroo.utils.ui.ConfigEditor;
@@ -268,7 +270,7 @@ public class BookPopup extends JPopupMenu {
                                                protected Void doInBackground() throws Exception {
                                                        for (BookInfo book : selected) {
                                                                lib.clearFromCache(book.getMeta().getLuid());
-                                                               BookCoverImager.clearIcon(book);
+                                                               CoverImager.clearIcon(book);
                                                        }
                                                        return null;
                                                }
@@ -685,18 +687,11 @@ public class BookPopup extends JPopupMenu {
                delete.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
-                               // final GuiReaderBook selectedBook =
-                               // mainPanel.getSelectedBook();
-                               // if (selectedBook != null) {
-                               // mainPanel.outOfUi(null, false, new Runnable() {
-                               // @Override
-                               // public void run() {
-                               // new GuiReaderPropertiesFrame(lib,
-                               // selectedBook.getInfo().getMeta())
-                               // .setVisible(true);
-                               // }
-                               // });
-                               // }
+                               BookInfo selected = informer.getUniqueSelected();
+                               if (selected != null) {
+                                       new PropertiesFrame(lib, selected.getMeta())
+                                                       .setVisible(true);
+                               }
                        }
                });
 
index 2e88c638956d67fc3cc296e456acdd35fe59bdcd..1123463119aa810c4309b705cb910939f570b6a0 100644 (file)
@@ -9,6 +9,7 @@ import java.awt.Rectangle;
 import javax.swing.JLabel;
 import javax.swing.SwingUtilities;
 
+import be.nikiroo.fanfix_swing.gui.utils.CoverImager;
 import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel;
 import be.nikiroo.utils.Progress;
 import be.nikiroo.utils.Progress.ProgressListener;
@@ -44,21 +45,6 @@ public class ImporterItem extends ListenerPanel {
                init(pg);
        }
 
-       static public Color getBackground(boolean enabled, boolean selected,
-                       boolean hovered) {
-               Color color = new Color(255, 255, 255, 0);
-               if (!enabled) {
-               } else if (selected && !hovered) {
-                       color = new Color(80, 80, 100, 40);
-               } else if (!selected && hovered) {
-                       color = new Color(230, 230, 255, 100);
-               } else if (selected && hovered) {
-                       color = new Color(200, 200, 255, 100);
-               }
-
-               return color;
-       }
-
        public String getStoryName() {
                return basename + ": " + storyName;
        }
@@ -79,7 +65,8 @@ public class ImporterItem extends ListenerPanel {
        public void setSelected(boolean selected) {
                if (this.selected != selected) {
                        this.selected = selected;
-                       setBackground(getBackground(isEnabled(), selected, hovered));
+                       setBackground(
+                                       CoverImager.getBackground(isEnabled(), selected, hovered));
                }
        }
 
@@ -90,7 +77,8 @@ public class ImporterItem extends ListenerPanel {
        public void setHovered(boolean hovered) {
                if (this.hovered != hovered) {
                        this.hovered = hovered;
-                       setBackground(getBackground(isEnabled(), selected, hovered));
+                       setBackground(
+                                       CoverImager.getBackground(isEnabled(), selected, hovered));
                }
        }
 
@@ -98,7 +86,8 @@ public class ImporterItem extends ListenerPanel {
        public void setEnabled(boolean enabled) {
                if (isEnabled() != enabled) {
                        super.setEnabled(enabled);
-                       setBackground(getBackground(isEnabled(), selected, hovered));
+                       setBackground(
+                                       CoverImager.getBackground(isEnabled(), selected, hovered));
                }
        }
 
diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/CoverImager.java b/src/be/nikiroo/fanfix_swing/gui/utils/CoverImager.java
new file mode 100644 (file)
index 0000000..93df707
--- /dev/null
@@ -0,0 +1,182 @@
+package be.nikiroo.fanfix_swing.gui.utils;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+
+import javax.imageio.ImageIO;
+
+import be.nikiroo.fanfix.Instance;
+import be.nikiroo.fanfix.library.BasicLibrary;
+import be.nikiroo.fanfix_swing.gui.book.BookInfo;
+import be.nikiroo.utils.Image;
+import be.nikiroo.utils.ui.ImageUtilsAwt;
+import be.nikiroo.utils.ui.UIUtils;
+
+/**
+ * This class can create a cover icon ready to use for the graphical
+ * application.
+ * 
+ * @author niki
+ */
+public class CoverImager {
+       // TODO: export some of the configuration options?
+       static final int COVER_WIDTH = 100;
+       static final int COVER_HEIGHT = 150;
+       static final int SPINE_WIDTH = 5;
+       static final int SPINE_HEIGHT = 5;
+       static final int HOFFSET = 20;
+       static final Color SPINE_COLOR_BOTTOM = new Color(180, 180, 180);
+       static final Color SPINE_COLOR_RIGHT = new Color(100, 100, 100);
+       static final Color BORDER = Color.black;
+
+       public static final int TEXT_HEIGHT = 50;
+       public static final int TEXT_WIDTH = COVER_WIDTH + 40;
+
+       //
+
+       static public Color getBackground(boolean enabled, boolean selected,
+                       boolean hovered) {
+               Color color = new Color(255, 255, 255, 0);
+               if (!enabled) {
+               } else if (selected && !hovered) {
+                       color = new Color(80, 80, 100, 40);
+               } else if (!selected && hovered) {
+                       color = new Color(230, 230, 255, 100);
+               } else if (selected && hovered) {
+                       color = new Color(200, 200, 255, 100);
+               }
+
+               return color;
+       }
+
+       /**
+        * The width of a cover image.
+        * 
+        * @return the width
+        */
+       static public int getCoverWidth() {
+               return SPINE_WIDTH + COVER_WIDTH;
+       }
+
+       /**
+        * The height of a cover image.
+        * 
+        * @return the height
+        */
+       static public int getCoverHeight() {
+               return COVER_HEIGHT + HOFFSET;
+       }
+
+       /**
+        * Generate a cover icon based upon the given {@link GuiReaderBookInfo}.
+        * 
+        * @param lib
+        *            the library the meta comes from (can be NULL)
+        * @param info
+        *            the {@link GuiReaderBookInfo}
+        * 
+        * @return the image
+        */
+       static public java.awt.Image generateCoverImage(BasicLibrary lib,
+                       BookInfo info) {
+               BufferedImage resizedImage = null;
+               String id = getIconId(info);
+
+               InputStream in = Instance.getInstance().getCache().getFromCache(id);
+               if (in != null) {
+                       try {
+                               resizedImage = ImageUtilsAwt.fromImage(new Image(in));
+                               in.close();
+                               in = null;
+                       } catch (IOException e) {
+                               Instance.getInstance().getTraceHandler().error(e);
+                       }
+               }
+
+               if (resizedImage == null) {
+                       try {
+                               Image cover = null;
+                               if (info != null) {
+                                       cover = info.getBaseImage(lib);
+                               }
+
+                               resizedImage = new BufferedImage(getCoverWidth(),
+                                               getCoverHeight(), BufferedImage.TYPE_4BYTE_ABGR);
+
+                               Graphics2D g = resizedImage.createGraphics();
+                               try {
+                                       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();
+                               }
+
+                               // Only save image with a cover, not the X thing
+                               if (id != null && cover != null) {
+                                       ByteArrayOutputStream out = new ByteArrayOutputStream();
+                                       ImageIO.write(resizedImage, "png", out);
+                                       byte[] imageBytes = out.toByteArray();
+                                       in = new ByteArrayInputStream(imageBytes);
+                                       Instance.getInstance().getCache().addToCache(in, id);
+                                       in.close();
+                                       in = null;
+                               }
+                       } catch (MalformedURLException e) {
+                               Instance.getInstance().getTraceHandler().error(e);
+                       } catch (IOException e) {
+                               Instance.getInstance().getTraceHandler().error(e);
+                       }
+               }
+
+               return resizedImage;
+       }
+
+       /**
+        * Manually clear the icon set for this item.
+        * 
+        * @param info
+        *            the info about the story or source/type or author
+        */
+       static public void clearIcon(BookInfo info) {
+               String id = getIconId(info);
+               Instance.getInstance().getCache().removeFromCache(id);
+       }
+
+       /**
+        * Get a unique ID from this {@link GuiReaderBookInfo} (note that it can be
+        * a story, a fake item for a source/type or a fake item for an author).
+        * 
+        * @param info
+        *            the info or NULL for a generic (non unique!) ID
+        * @return the unique ID
+        */
+       static private String getIconId(BookInfo info) {
+               return (info == null ? "" : info.getId() + ".") + "book-thumb_"
+                               + SPINE_WIDTH + "x" + COVER_WIDTH + "+" + SPINE_HEIGHT + "+"
+                               + COVER_HEIGHT + "@" + HOFFSET;
+       }
+}