Better caching of images, better api (change graphic -> image) to make

more sense. Set the default image names to be static strings, so it's
easier to know what they are without knowing specific details.
This commit is contained in:
nathan 2017-09-03 17:34:09 +02:00
parent cdbf8a2a4d
commit 289e83ba63
5 changed files with 93 additions and 61 deletions

View File

@ -18,7 +18,6 @@ package dorkbox.notify;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
@ -43,7 +42,7 @@ class AsDialog extends JDialog implements INotify {
// this is on the swing EDT
@SuppressWarnings("NumericCastThatLosesPrecision")
AsDialog(final Notify notification, final Image image, final ImageIcon imageIcon, final Window container, final Theme theme) {
AsDialog(final Notify notification, final ImageIcon image, final Window container, final Theme theme) {
super(container, Dialog.ModalityType.MODELESS);
this.notification = notification;
@ -60,7 +59,7 @@ class AsDialog extends JDialog implements INotify {
setTitle(notification.title);
setResizable(false);
NotifyCanvas notifyCanvas = new NotifyCanvas(notification, imageIcon, theme);
NotifyCanvas notifyCanvas = new NotifyCanvas(notification, image, theme);
add(notifyCanvas);
look = new LookAndFeel(this, notifyCanvas, notification, image, container.getBounds());

View File

@ -18,7 +18,6 @@ package dorkbox.notify;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
@ -42,7 +41,7 @@ class AsFrame extends JFrame implements INotify {
// this is on the swing EDT
@SuppressWarnings("NumericCastThatLosesPrecision")
AsFrame(final Notify notification, final Image image, final ImageIcon imageIcon, final Theme theme) {
AsFrame(final Notify notification, final ImageIcon image, final Theme theme) {
this.notification = notification;
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
@ -90,7 +89,7 @@ class AsFrame extends JFrame implements INotify {
.getBounds();
NotifyCanvas notifyCanvas = new NotifyCanvas(notification, imageIcon, theme);
NotifyCanvas notifyCanvas = new NotifyCanvas(notification, image, theme);
getContentPane().add(notifyCanvas);
look = new LookAndFeel(this, notifyCanvas, notification, image, bounds);

View File

@ -15,7 +15,6 @@
*/
package dorkbox.notify;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseAdapter;
@ -25,6 +24,8 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import javax.swing.ImageIcon;
import dorkbox.tweenengine.BaseTween;
import dorkbox.tweenengine.Tween;
import dorkbox.tweenengine.TweenCallback;
@ -91,7 +92,7 @@ class LookAndFeel {
LookAndFeel(final Window parent,
final NotifyCanvas notifyCanvas,
final Notify notification,
final Image image,
final ImageIcon image,
final Rectangle parentBounds) {
this.parent = parent;
@ -123,7 +124,7 @@ class LookAndFeel {
anchorY = getAnchorY(position, parentBounds);
if (image != null) {
parent.setIconImage(image);
parent.setIconImage(image.getImage());
}
else {
parent.setIconImage(SwingUtil.BLANK_ICON);

View File

@ -21,6 +21,7 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
@ -28,6 +29,7 @@ import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import dorkbox.util.ActionHandler;
import dorkbox.util.ImageUtil;
import dorkbox.util.LocationResolver;
import dorkbox.util.Property;
import dorkbox.util.SwingUtil;
@ -55,6 +57,12 @@ import dorkbox.util.Version;
public final
class Notify {
public static final String DIALOG_CONFIRM = "dialog-confirm.png";
public static final String DIALOG_INFORMATION = "dialog-information.png";
public static final String DIALOG_WARNING = "dialog-warning.png";
public static final String DIALOG_ERROR = "dialog-error.png";
/**
* This is the title font used by a notification.
*/
@ -79,8 +87,7 @@ class Notify {
@Property
public static String IMAGE_PATH = "resources";
private static Map<String, BufferedImage> imageCache = new HashMap<String, BufferedImage>(4);
private static Map<String, ImageIcon> imageIconCache = new HashMap<String, ImageIcon>(4);
private static Map<String, SoftReference<ImageIcon>> imageCache = new HashMap<String, SoftReference<ImageIcon>>(4);
/**
* Gets the version number.
@ -98,38 +105,69 @@ class Notify {
return new Notify();
}
/**
* Gets the size of the image to be used in the notification, which is a 48x48 pixel image.
*/
public static
int getImageSize() {
return 48;
}
/**
* Permits one to override the default images for the dialogs. This is NOT thread safe, and must be performed BEFORE showing a
* notification.
* <p>
* The image names are as follows:
* <p>
* 'dialog-confirm.png' 'dialog-error.png' 'dialog-information.png' 'dialog-warning.png'
* 'Notify.DIALOG_CONFIRM' 'Notify.DIALOG_INFORMATION' 'Notify.DIALOG_WARNING' 'Notify.DIALOG_ERROR'
*
* @param imageName the name of the image, either your own if you want want it cached, or one of the above.
* @param image the BufferedImage that you want to cache.
*/
public static
void setImagePath(String imageName, BufferedImage image) {
void overrideDefaultImage(String imageName, BufferedImage image) {
if (imageCache.containsKey(imageName)) {
throw new RuntimeException("Unable to set an image that already has been set. This action must be done as soon as possible.");
}
imageCache.put(imageName, image);
Image imageImmediate = ImageUtil.getImageImmediate(image);
// we only use 48x48 pixel images. Resize as necessary
int width = imageImmediate.getWidth(null);
int height = imageImmediate.getHeight(null);
BufferedImage bufferedImage;
// resize the image, keep aspect ratio
if (width > height) {
bufferedImage = ImageUtil.resizeImage(image, getImageSize(), -1);
}
else {
bufferedImage = ImageUtil.resizeImage(image, -1, getImageSize());
}
imageCache.put(imageName, new SoftReference<ImageIcon>(new ImageIcon(bufferedImage)));
}
private static
BufferedImage getImage(String imageName) {
BufferedImage bufferedImage = imageCache.get(imageName);
ImageIcon getImage(String imageName) {
ImageIcon image = null;
InputStream resourceAsStream = null;
try {
if (bufferedImage == null) {
SoftReference<ImageIcon> reference = imageCache.get(imageName);
if (reference != null) {
image = reference.get();
}
if (image == null) {
String name = IMAGE_PATH + File.separatorChar + imageName;
resourceAsStream = LocationResolver.getResourceAsStream(name);
bufferedImage = ImageIO.read(resourceAsStream);
imageCache.put(imageName, bufferedImage);
image = new ImageIcon(ImageUtil.getImageImmediate(ImageIO.read(resourceAsStream)));
imageCache.put(imageName, new SoftReference<ImageIcon>(image));
}
} catch (IOException e) {
e.printStackTrace();
@ -143,7 +181,7 @@ class Notify {
}
}
return bufferedImage;
return image;
}
@ -158,7 +196,7 @@ class Notify {
boolean hideCloseButton;
boolean isDark = false;
int screenNumber = Short.MIN_VALUE;
private Image graphic;
private ImageIcon icon;
ActionHandler<Notify> onCloseAction;
private INotify notifyPopup;
@ -191,11 +229,24 @@ class Notify {
}
/**
* Specifies the graphic
* Specifies the image
*/
public
Notify graphic(Image graphic) {
this.graphic = graphic;
Notify image(Image image) {
// we only use 48x48 pixel images. Resize as necessary
int width = image.getWidth(null);
int height = image.getHeight(null);
BufferedImage bufferedImage = ImageUtil.getBufferedImage(image);
// resize the image, keep aspect ratio
if (width > height) {
bufferedImage = ImageUtil.resizeImage(bufferedImage, 48, -1);
} else {
bufferedImage = ImageUtil.resizeImage(bufferedImage, -1, 48);
}
this.icon = new ImageIcon(bufferedImage);
return this;
}
@ -259,47 +310,48 @@ class Notify {
}
/**
* Shows the notification with the built-in 'warning' graphic.
* Shows the notification with the built-in 'warning' image.
*/
public
void showWarning() {
name = "dialog-warning.png";
graphic(getImage(name));
name = DIALOG_WARNING;
icon = getImage(name);
show();
}
/**
* Shows the notification with the built-in 'information' graphic.
* Shows the notification with the built-in 'information' image.
*/
public
void showInformation() {
name = "dialog-information.png";
graphic(getImage(name));
name = DIALOG_INFORMATION;
icon = getImage(name);
show();
}
/**
* Shows the notification with the built-in 'error' graphic.
* Shows the notification with the built-in 'error' image.
*/
public
void showError() {
name = "dialog-error.png";
graphic(getImage(name));
name = DIALOG_ERROR;
icon = getImage(name);
show();
}
/**
* Shows the notification with the built-in 'confirm' graphic.
* Shows the notification with the built-in 'confirm' image.
*/
public
void showConfirm() {
name = "dialog-confirm.png";
graphic(getImage(name));
name = DIALOG_CONFIRM;
icon = getImage(name);
show();
}
/**
* Shows the notification. If the Notification is assigned to a screen, but shown in a JFrame, the screen number will be ignored.
* Shows the notification. If the Notification is assigned to a screen, but shown inside a Swing/etc parent, the screen number will be
* ignored.
*/
public
void show() {
@ -310,26 +362,7 @@ class Notify {
public
void run() {
final Notify notify = Notify.this;
final Image graphic = notify.graphic;
// we ONLY cache our own icons
ImageIcon imageIcon = null;
if (graphic != null) {
if (name != null) {
imageIcon = imageIconCache.get(name);
if (imageIcon == null) {
Image image = new ImageIcon(graphic).getImage();
// have to do this twice, so that it will finish loading the image (weird callback stuff is required if we don't do this)
imageIcon = new ImageIcon(image);
imageIconCache.put(name, imageIcon);
}
}
else {
imageIcon = new ImageIcon(graphic);
}
}
final ImageIcon image = notify.icon;
Theme theme;
if (notify.theme != null) {
@ -340,9 +373,9 @@ class Notify {
}
if (window == null) {
notifyPopup = new AsFrame(notify, graphic, imageIcon, theme);
notifyPopup = new AsFrame(notify, image, theme);
} else {
notifyPopup = new AsDialog(notify, graphic, imageIcon, window, theme);
notifyPopup = new AsDialog(notify, image, window, theme);
}
notifyPopup.setVisible(true);
@ -354,7 +387,7 @@ class Notify {
});
// don't need to hang onto these.
graphic = null;
icon = null;
}
/**

View File

@ -126,7 +126,7 @@ class NotifyTest {
.hideAfter(13000)
.position(Pos.BOTTOM_LEFT)
// .setScreen(0)
.darkStyle()
// .darkStyle()
// .shake(1300, 4)
// .shake(1300, 10)
.hideCloseButton()