package org.xmind.ui.internal.mindmap;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.xmind.core.Core;
import org.xmind.core.util.FileUtils;
import org.xmind.ui.internal.MindMapUIPlugin;
import org.xmind.ui.io.DownloadJob;
import org.xmind.ui.io.UIJobChangeListener;
import org.xmind.ui.mindmap.IMindMapImages;
import org.xmind.ui.mindmap.MindMapUI;
public class ImageDownloader {
private class ImageDownload extends UIJobChangeListener {
private String url;
private IStatus status;
private ImageDescriptor image;
private File tempFile;
private DownloadJob job;
private List<Runnable> notifiers = new ArrayList<Runnable>();
public ImageDownload(String url) {
this.url = url;
startDownload();
}
private void startDownload() {
String fileExtension;
try {
URI uri = new URI(url);
fileExtension = FileUtils.getExtension(uri.getPath());
} catch (URISyntaxException e) {
fileExtension = FileUtils.getExtension(url);
}
this.tempFile = Core.getWorkspace().createTempFile(
"imageDownload", "", fileExtension); //$NON-NLS-1$ //$NON-NLS-2$
this.job = new DownloadJob(NLS.bind("Download Image From ''{0}''", //$NON-NLS-1$
url), url, tempFile.getAbsolutePath(), MindMapUI.PLUGIN_ID);
this.job.addJobChangeListener(this);
this.job.schedule(50);
this.status = new Status(IStatus.INFO, MindMapUI.PLUGIN_ID,
NLS.bind("Downloading image from ''{0}''", url)); //$NON-NLS-1$
this.image = getCurrentBusyImage();
}
public void addNotifier(Runnable notifier) {
notifiers.add(notifier);
if (notifiers.size() > 0) {
if (status.getSeverity() != IStatus.OK
&& status.getSeverity() != IStatus.INFO) {
startDownload();
}
if (status.getSeverity() == IStatus.INFO) {
busyDownloads.add(this);
}
}
}
public void removeNotifier(Runnable notifier) {
notifiers.remove(notifier);
if (status.getSeverity() != IStatus.INFO || notifiers.size() <= 0) {
busyDownloads.remove(this);
}
}
protected void doDone(IJobChangeEvent event) {
busyDownloads.remove(this);
int code = event.getResult().getSeverity();
if (code == IStatus.OK) {
onSuccess();
} else if (code == IStatus.CANCEL) {
onCancel();
} else {
onFailed(event.getResult());
}
}
private void onSuccess() {
try {
this.status = new Status(IStatus.OK, MindMapUI.PLUGIN_ID,
NLS.bind("Image downloaded from ''{0}''", url)); //$NON-NLS-1$
setImage(ImageDescriptor
.createFromURL(tempFile.toURI().toURL()));
} catch (MalformedURLException e) {
this.status = new Status(
IStatus.ERROR,
MindMapUI.PLUGIN_ID,
NLS.bind(
"Failed to parse the temp file path for the downloaded image ''{0}''", //$NON-NLS-1$
url), e);
MindMapUIPlugin.getDefault().getLog().log(this.status);
setImage(getWarningImage());
}
}
private void onFailed(IStatus result) {
this.status = new Status(
IStatus.ERROR,
MindMapUI.PLUGIN_ID,
NLS.bind(
"Failed to download image from ''{0}'' due to ''{1}''", //$NON-NLS-1$
url, result.getMessage()), result.getException());
setImage(getWarningImage());
}
private void onCancel() {
this.status = new Status(IStatus.CANCEL, MindMapUI.PLUGIN_ID,
NLS.bind("Image download canceled from ''{0}''", url)); //$NON-NLS-1$
setImage(getWarningImage());
}
public void setImage(ImageDescriptor newImage) {
this.image = newImage;
callNotifiers();
}
private void callNotifiers() {
Object[] notifierArray = notifiers.toArray();
for (final Object notifier : notifierArray) {
try {
((Runnable) notifier).run();
} catch (Throwable e) {
MindMapUIPlugin
.getDefault()
.getLog()
.log(new Status(IStatus.WARNING,
MindMapUI.PLUGIN_ID,
"Failed to call one notifier when image downloaded from '" //$NON-NLS-1$
+ url + "'", e)); //$NON-NLS-1$
}
}
}
public ImageDescriptor getImage() {
return image;
}
public IStatus getStatus() {
return status;
}
}
private static final int ROTATION_INTERVALS = 200;
private static final ImageDownloader instance = new ImageDownloader();
private Map<String, ImageDownload> downloads = new HashMap<String, ImageDownload>();
private Set<ImageDownload> busyDownloads = new HashSet<ImageDownload>();
private List<ImageDescriptor> busyImages = null;
private ImageDescriptor warningImage = null;
private int busyImageIndex = 0;
private boolean rotatingBusyImages = false;
private Runnable rotateBusyImages = new Runnable() {
public void run() {
rotateBusyImages();
}
};
private ImageDownloader() {
}
public void register(String url, Runnable notifier) {
ImageDownload download = downloads.get(url);
if (download == null) {
download = new ImageDownload(url);
downloads.put(url, download);
}
download.addNotifier(notifier);
checkBusyImageRotation();
}
public void unregister(String url, Runnable notifier) {
ImageDownload download = downloads.get(url);
if (download != null) {
download.removeNotifier(notifier);
}
checkBusyImageRotation();
}
public ImageDescriptor getImage(String url) {
ImageDownload download = downloads.get(url);
if (download != null)
return download.getImage();
return null;
}
public IStatus getStatus(String url) {
ImageDownload download = downloads.get(url);
if (download != null)
return download.getStatus();
return null;
}
private void checkBusyImageRotation() {
if (busyDownloads.size() > 0) {
if (!rotatingBusyImages) {
asyncRunInUI(new Runnable() {
public void run() {
Display.getCurrent().timerExec(ROTATION_INTERVALS,
rotateBusyImages);
}
});
}
rotatingBusyImages = true;
} else {
rotatingBusyImages = false;
}
}
private void rotateBusyImages() {
if (!rotatingBusyImages)
return;
busyImageIndex++;
if (busyImageIndex >= busyImages.size()) {
busyImageIndex = 0;
}
Object[] busyDownloadsArray = busyDownloads.toArray();
for (Object download : busyDownloadsArray) {
((ImageDownload) download).setImage(getCurrentBusyImage());
}
Display.getCurrent().timerExec(ROTATION_INTERVALS, rotateBusyImages);
}
private void asyncRunInUI(final Runnable runnable) {
Display display = Display.getCurrent();
if (display == null)
display = Display.getDefault();
if (display != null) {
display.asyncExec(runnable);
}
}
private List<ImageDescriptor> getBusyImages() {
if (busyImages == null) {
busyImages = findBusyImages();
}
return busyImages;
}
private ImageDescriptor getWarningImage() {
if (warningImage == null)
warningImage = ImageDescriptor.createFromImage(Display.getCurrent()
.getSystemImage(SWT.ICON_WARNING));
return warningImage;
}
private List<ImageDescriptor> findBusyImages() {
List<ImageDescriptor> list = new ArrayList<ImageDescriptor>();
for (int index = 1; index <= 12; index++) {
String path = String.format("/icons/busy/busy_f%02d.gif", index); //$NON-NLS-1$
ImageDescriptor img = AbstractUIPlugin.imageDescriptorFromPlugin(
"org.xmind.ui.browser", path); //$NON-NLS-1$
if (img != null) {
list.add(img);
}
}
if (list.isEmpty()) {
list.add(MindMapUI.getImages().get(IMindMapImages.STOP, true));
}
return list;
}
private ImageDescriptor getCurrentBusyImage() {
return getBusyImages().get(busyImageIndex);
}
public static ImageDownloader getInstance() {
return instance;
}
}