| Summary: | ImageProvider extension point could be more flexible | ||
|---|---|---|---|
| Product: | [Modeling] Graphiti | Reporter: | Rhett Hudson <rhett.hudson> |
| Component: | Core | Assignee: | Felix Velasco <felix.velasco> |
| Status: | CLOSED WORKSFORME | QA Contact: | |
| Severity: | enhancement | ||
| Priority: | P3 | CC: | felix.velasco, hal, michael.wenz, rcernich |
| Version: | 0.8.0 | ||
| Target Milestone: | --- | ||
| Hardware: | All | ||
| OS: | All | ||
| Whiteboard: | |||
|
Description
Rhett Hudson
Turns out getPluginId() is final, so overriding it won't work. The lack of atomicity between getPluginId() and getImageFilePath() made it highly implementation dependent anyway. As I try to work my way around this, I've realized that not only do the plugins that extend my editor have to depend on Graphiti to extend the image provider extension point, but my editor which extends diagramTypeProviders has to include a reference to the id of the image providers that they extend. That means that my editor plugin has to have prior knowledge of the things that extend it. Which breaks my use case. I need to be able to register something like an IImageProvider that gets passed an id and is responsible for returning the Image. I have a similar requirement. One possible solution is to add a documentTypeExtension extension point that allows other plugins to contribute functionality within the scope of a specific document type. I propose this extension point mirror documentTypeProvider in all aspects except the actual provider part. This would allow the existing parse code to be reused. I'm effectively using a HACKY version of this whereby additional plugins redeclare documentTypeProvider but do not provide an implementation. This allows their image providers to be loaded when that specific document type is loaded. It would be nice if there were a safer way to do this. Best, Rob If you could support general URLs including platform:/plugin and platform:/resource instead of just paths relative to a plugin, I think most of these use cases would be handled. E.g. if you create your own extension point that lets other plugins provide new images, you can add a platform:/plugin/<bundleId> prefix to provided plugin-relative path.
This means the implementation may need a more powerful ImageDescriptor, in general reading from a URL. Here's one:
package org.ptolemy.graphiti.editor.jface;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.ImageData;
/**
* ImageDescriptor that downloads the image data from a URL
* Typically used by a LabelProvider with an ImageRegistry to provide icons.
* @see LabelProvider
* @see ImageRegistry
* @author hal
*
*/
public class URLImageDescriptor extends ImageDescriptor {
private URL url;
public URLImageDescriptor(URL url) {
this.url = url;
}
public URLImageDescriptor(String urlString) throws MalformedURLException {
this(new URL(urlString));
}
public URLImageDescriptor(URI uri) throws MalformedURLException {
this(uri.toURL());
}
@Override
public String toString() {
return "[URLImageDescriptor @ " + getUrl() + "]";
}
public URL getUrl() {
return url;
}
@Override
public ImageData getImageData() {
try {
return getImageData(getUrl());
} catch (Exception e) {
return null;
}
}
public ImageData getImageData(URL url) {
InputStream inputStream = null;
try {
inputStream = url.openStream();
return new ImageData(inputStream);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
} catch (IOException e) {
throw new IllegalArgumentException(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
}
}
An alternative way to add images from other plugins could be to use PlatformGraphicsAlgorithms as described in http://www.eclipse.org/forums/index.php/mv/msg/389722/934103/#msg_934103 (In reply to comment #5) > An alternative way to add images from other plugins could be to use > PlatformGraphicsAlgorithms as described in > http://www.eclipse.org/forums/index.php/mv/msg/389722/934103/#msg_934103 Wouldn't that require the plugin providing the editor to also provide an extension point for registering image providers? The plugin providing the images won't be providing a DiagramTypeProvider. Some background: My specific usecase relates to adding support for a custom task into the BPMN2 modeller. To support this today, I provide a documentTypeProvider extension that defines no class. This works, but it's definitely a hack. My suggestion about create a documentTypeExtension, was to create an interface for adding features to an existing document type provider, without overriding the type provider itself (i.e. use all the existing code that processes the type provider, but igonore class and name attributes). Just to a bit more specific about how to use PlatformGraphicsAlgorithms. I created a IGraphicsAlgorithmRendererFactory that retrieved the image from the id using ImageDescriptor's createFromURL method (jface has an internal ImageDescriptor class for URLs, and this is how you access it). From this I created an ImageFigure that I then wrapped in a Shape implementing IGraphicsAlgorithmRenderer. Since you can use platform:/plugin/ urls, this supports getting images from any plugin.
Here's the essential code:
public IGraphicsAlgorithmRenderer createGraphicsAlgorithmRenderer(IRendererContext rendererContext) {
String imageKey = rendererContext.getPlatformGraphicsAlgorithm().getId();
ImageRegistry imageRegistry = Activator.getDefault().getImageRegistry();
Image image = imageRegistry.get(imageKey);
if (image == null) {
imageRegistry.put(imageKey, ImageDescriptor.createFromURL(new URL(imageKey)));
image = imageRegistry.get(imageKey);
}
IFigure figure = null;
if (image != null) {
figure = new ImageFigure(image);
else {
figure = new Label(id);
}
return new GenericShapeRenderer(figure);
}
public class GenericShapeRenderer extends Shape implements IGraphicsAlgorithmRenderer {
public GenericShapeRenderer(IFigure... childFigures) {
for (IFigure childFigure : childFigures) {
add(childFigure);
}
}
@Override
public void setBounds(Rectangle rect) {
super.setBounds(rect);
for (Object figure : getChildren()) {
if (figure instanceof IFigure) {
((IFigure) figure).setSize(rect.width, rect.height);
}
}
}
@Override
protected void fillShape(Graphics graphics) {
}
@Override
protected void outlineShape(Graphics graphics) {
}
}
(In reply to comment #4) > If you could support general URLs including platform:/plugin and > platform:/resource instead of just paths relative to a plugin, I think most > of these use cases would be handled. E.g. if you create your own extension > point that lets other plugins provide new images, you can add a > platform:/plugin/<bundleId> prefix to provided plugin-relative path. > > This means the implementation may need a more powerful ImageDescriptor, in > general reading from a URL. Here's one: > The current implementation, without any change, already supports arbitrary URLs, including platform:/plugin, platform:/resource, and Bundle.getEntry urls. You can try any of this options: URI myURI = URI.createPlatformPluginURI("plugin-id/icons/toad.png", true); addImageFilePath("Toad", myURI.toString()); URI myURI2 = URI.createPlatformResourceURI("/Test/Frog.png", true); addImageFilePath("Frog", myURI2.toString()); Bundle bundle = Platform.getBundle("plugin-in"); addImageFilePath("bird", bundle.getEntry("icons/bird.jpg").toString()); IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember("/Test/mouse.png"); addImageFilePath("mouse", res.getLocationURI().toString()); Please note that URI in the two first examples is org.eclipse.emf.common.util.URI, from the EMF Framework, not the java.net one. Bug 396247 has been filled to review the relation between DTPs and ImageProviders. Further improvements will be tracked there. If the workaround of comment #8 doesn't cover your use cases, please comment in the new bug. With Felix comment on this I would close this with worksforme rather than fixed, as no changes have been done. |