package com.peterhi.ui;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import com.peterhi.InvocationAdapter;
public final class Ui {
public static final Font FONT_PLAIN;
public static final Font FONT_BOLD;
public static final Color BLACK;
public static final Color WHITE;
public static final Color RED;
public static final Color YELLOW;
public static final Color BLUE;
public static final Color GREEN;
public static final Color CONTROL;
public static final Color ROYAL_BLUE;
static {
Display d = Display.getDefault();
FONT_PLAIN = d.getSystemFont();
FONT_BOLD = new Font(d, FONT_PLAIN.getFontData()[0].getName(),
FONT_PLAIN.getFontData()[0].getHeight(),
FONT_PLAIN.getFontData()[0].getStyle() | SWT.BOLD);
BLACK = d.getSystemColor(SWT.COLOR_BLACK);
WHITE = d.getSystemColor(SWT.COLOR_WHITE);
RED = d.getSystemColor(SWT.COLOR_RED);
YELLOW = d.getSystemColor(SWT.COLOR_YELLOW);
BLUE = d.getSystemColor(SWT.COLOR_BLUE);
GREEN = d.getSystemColor(SWT.COLOR_GREEN);
CONTROL = d.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
ROYAL_BLUE = new Color(d, 65, 105, 225);
}
private static ImageStore store;
private static ImageStore getStore() {
if (store == null) {
store = new ImageStore();
}
return store;
}
public static boolean isDisposed(Object object) {
if (object == null) {
return true;
}
try {
Class<?> type = object.getClass();
Method isDisposed = type.getMethod("isDisposed");
return (Boolean )isDisposed.invoke(object);
} catch (Exception ex) {
ex.printStackTrace();
return true;
}
}
public static void dispose(Object object) {
if (object == null) {
return;
}
try {
Class<?> type = object.getClass();
Method dispose = type.getMethod("dispose");
dispose.invoke(object);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Image[] lease(URL url) {
if (url == null) {
throw new IllegalArgumentException("Null url.");
}
ImageEntry entry = getStore().get(url);
if (entry == null) {
try {
Display d = Display.getCurrent();
String file = url.getFile().toLowerCase();
if (file.endsWith(".zip")) {
SortedMap<String, ByteArrayOutputStream> byname =
new TreeMap<String, ByteArrayOutputStream>();
InputStream stream = url.openStream();
ZipInputStream zip = new ZipInputStream(stream);
ZipEntry zentry = null;
byte[] buffer = new byte[8192];
int read;
while ((zentry = zip.getNextEntry()) != null) {
String name = zentry.getName();
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((read = zip.read(buffer)) != 1) {
out.write(buffer, 0, read);
}
byname.put(name, out);
zip.closeEntry();
}
zip.close();
Image[] multi = new Image[byname.size()];
int counter = 0;
for (ByteArrayOutputStream out : byname.values()) {
byte[] data = out.toByteArray();
ByteArrayInputStream in =
new ByteArrayInputStream(data);
multi[counter] = new Image(d, in);
counter++;
}
entry = new ImageEntry(multi);
} else {
InputStream stream = url.openStream();
Image single = new Image(d, stream);
entry = new ImageEntry(single);
}
getStore().put(url, entry);
} catch (IOException ex) {
throw new SWTException(SWT.ERROR_IO, ex.toString());
}
}
entry.incrementCounter();
return entry.getImages();
}
public static void release(Image...images) {
if (images == null || images.length < 1) {
throw new IllegalArgumentException(
"Images mustn't be null and it must contain at least one.");
}
for (Iterator<Map.Entry<URL, ImageEntry>> itor =
getStore().entrySet().iterator();
itor.hasNext();) {
Map.Entry<URL, ImageEntry> entry = itor.next();
ImageEntry ientry = entry.getValue();
if (Arrays.deepEquals(images, ientry.getImages())) {
if (ientry.decrementCounter() == 0) {
itor.remove();
}
}
}
}
public static void releaseAll() {
for (ImageEntry entry : getStore().values()) {
Ui.dispose(entry);
}
getStore().clear();
}
public static <T> T getImages(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Null type.");
}
return new InvocationAdapter<T>(type) {
@Override
protected Object invoke(Method method, Object[] args)
throws Throwable {
String name = method.getName();
String folder = "/" +
getType().getPackage().getName().replaceAll("\\.", "/");
String path = folder + "/" + name;
Class<?> rtype = method.getReturnType();
if (rtype == Image.class) {
URL url = getClass().getResource(path + ".png");
if (url == null) {
System.out.println(path + ".png");
throw new SWTException(SWT.ERROR_IO,
MessageFormat.format("Image \"{0}\" not found.",
name));
}
return lease(url)[0];
}
if (rtype == Image[].class) {
URL url = getClass().getResource(path + ".zip");
if (url == null) {
throw new SWTException(SWT.ERROR_IO,
MessageFormat.format("Image \"{0}\" not found.",
name));
}
return lease(url);
}
throw new SWTException(SWT.ERROR_IO, MessageFormat.format(
"Invalid method to get image \"{0}\".", method));
}
}.createProxy();
}
}
final class ImageStore extends HashMap<URL, ImageEntry> {
private static final long serialVersionUID = 301047279286084768L;
}
final class ImageEntry {
private final Image[] images;
private int counter;
public ImageEntry(Image...images) {
if (images == null || images.length < 1) {
throw new IllegalArgumentException(
"Images mustn't be null, and must contain at least one image.");
}
this.images = images;
}
public Image[] getImages() {
return images;
}
public int incrementCounter() {
counter++;
return counter;
}
public int decrementCounter() {
counter--;
if (counter == 0) {
Ui.dispose(this);
}
return counter;
}
public boolean isDisposed() {
for (Image image : images) {
if (!image.isDisposed()) {
return false;
}
}
return true;
}
public void dispose() {
for (Image image : images) {
Ui.dispose(image);
}
}
}