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); } }); } } }