package org.bndtools.core.ui.wizards.shared;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.bndtools.templating.Template;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.widgets.Control;
import aQute.lib.io.IO;
import bndtools.Plugin;
/*
* Loads icons from the templates in a background job, and updates the UI in batches when icons become available.
*/
public class IconLoaderJob extends Job {
private final ILog log = Plugin.getDefault().getLog();
private final Collection<Template> templates;
private final int batchLimit;
private final StructuredViewer viewer;
private final Map<Template,Image> loadedImageMap;
public IconLoaderJob(Collection<Template> templates, StructuredViewer viewer, Map<Template,Image> loadedImageMap, int batchLimit) {
super("load template icons");
this.templates = templates;
this.viewer = viewer;
this.loadedImageMap = loadedImageMap;
this.batchLimit = batchLimit;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
SubMonitor progress = SubMonitor.convert(monitor, templates.size());
Map<Template,byte[]> batch = new IdentityHashMap<>();
for (Template template : templates) {
InputStream iconStream = null;
try {
URI iconUri = template.getIcon();
if (iconUri != null) {
iconStream = iconUri.toURL().openStream();
byte[] bytes = IO.read(iconStream);
batch.put(template, bytes);
if (batch.size() >= batchLimit) {
processBatch(batch);
batch = new IdentityHashMap<>();
}
}
} catch (Exception e) {
log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0, "Error reading icon for template '" + template.getName() + "'", e));
} finally {
IO.close(iconStream);
}
progress.worked(1);
}
processBatch(batch);
return Status.OK_STATUS;
}
private void processBatch(final Map<Template,byte[]> batch) {
if (batch.isEmpty())
return;
final Control control = viewer.getControl();
if (control != null && !control.isDisposed()) {
control.getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (control.isDisposed())
return;
List<Object> toUpdate = new ArrayList<>(batch.size());
for (Entry<Template,byte[]> entry : batch.entrySet()) {
Template template = entry.getKey();
byte[] imgBytes = entry.getValue();
try {
ImageData imgData = new ImageData(new ByteArrayInputStream(imgBytes));
Image image = new Image(control.getDisplay(), imgData);
Image old = loadedImageMap.put(template, image);
if (old != null && !old.isDisposed())
old.dispose();
toUpdate.add(template);
} catch (Exception e) {
log.log(new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0, "Error loading image data for template icon: " + template.getName(), e));
}
}
viewer.update(toUpdate.toArray(), null);
}
});
}
}
}