/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.util;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageDataProvider;
import org.eclipse.swt.graphics.RGB;
import org.xmind.core.marker.IMarker;
import org.xmind.core.marker.IMarkerRef;
import org.xmind.core.marker.IMarkerResource;
import org.xmind.core.marker.IMarkerVariation;
import org.xmind.ui.internal.svgsupport.SVGImageData;
import org.xmind.ui.internal.svgsupport.SVGReference;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.resources.ImageUtils;
public class MarkerImageDescriptor extends ImageDescriptor {
public static final String RESOURCE_URL_PREFIX = "platform:/plugin/org.xmind.ui.resources/markers/"; //$NON-NLS-1$
private static ImageDescriptor ErrorImage = null;
private IMarker marker;
private IMarkerRef markerRef;
private String markerId;
private RGB background;
private boolean createByStream = true;
private int maxWidth;
private int maxHeigh;
protected MarkerImageDescriptor(IMarker marker, int maxWidth,
int maxHeigh) {
this.marker = marker;
this.markerRef = null;
this.markerId = marker.getId();
this.maxWidth = maxWidth;
this.maxHeigh = maxHeigh;
}
protected MarkerImageDescriptor(IMarkerRef markerRef, int maxWidth,
int maxHeigh) {
this.marker = null;
this.markerRef = markerRef;
this.markerId = markerRef.getMarkerId();
this.maxWidth = maxWidth;
this.maxHeigh = maxHeigh;
}
@Override
public Image createImage(boolean returnMissingImageOnError, Device device) {
Image image = null;
try {
image = new Image(device, new ImageDataProvider() {
@Override
public ImageData getImageData(int zoom) {
return MarkerImageDescriptor.this.getImageData(zoom);
}
});
} catch (SWTException e) {
if (e.code != SWT.ERROR_INVALID_IMAGE) {
throw e;
}
} catch (IllegalArgumentException e) {
// fall through
}
if (image == null && returnMissingImageOnError) {
try {
image = new Image(device, DEFAULT_IMAGE_DATA);
} catch (SWTException nextException) {
return null;
}
}
return image;
}
@Override
public ImageData getImageData() {
String svgPath = getMarker() == null ? null : getMarker().getSVGPath();
boolean createImageDataByStream = createByStream
|| (svgPath == null || "".equals(svgPath)); //$NON-NLS-1$
if (createImageDataByStream)
return createImageDataByStream(100);
else {
return createImageDataBySVG(100);
}
}
private ImageData getImageData(int zoom) {
if (zoom > 100) {
String svgPath = getMarker() == null ? null
: getMarker().getSVGPath();
boolean createImageDataByStream = createByStream
|| (svgPath == null || "".equals(svgPath)); //$NON-NLS-1$
if (createImageDataByStream)
return createImageDataByStream(200);
else {
return createImageDataBySVG(200);
}
} else {
return getImageData();
}
}
private ImageData createImageDataBySVG(int zoom) {
int width = zoom / 100 * maxWidth;
int height = zoom / 100 * maxHeigh;
String filePath = RESOURCE_URL_PREFIX + getMarker().getSVGPath();
SVGImageData data = new SVGReference(filePath).getSVGData();
return data.createImage(new Dimension(width, height), background);
}
private ImageData createImageDataByStream(int zoom) {
InputStream in = getStream(zoom);
ImageData result = null;
if (in != null) {
try {
result = new ImageData(in);
result = performScale(result);
} catch (SWTException e) {
Logger.log(e, "Unable to create image from marker: [" //$NON-NLS-1$
+ this.markerId + "] " //$NON-NLS-1$
+ (marker != null ? marker.getResourcePath() : "")); //$NON-NLS-1$
// if (e.code != SWT.ERROR_INVALID_IMAGE) {
// throw e;
// // fall through otherwise
// }
} finally {
try {
in.close();
} catch (IOException e) {
//System.err.println(getClass().getName()+".getImageData(): "+
// "Exception while closing InputStream : "+e);
}
}
}
if (result == null) {
result = getErrorImage().getImageData();
}
return result;
}
private ImageData performScale(ImageData result) {
if (maxWidth >= 0 || maxHeigh >= 0) {
double hScale = (double) result.width / maxWidth;
double vScale = (double) result.height / maxHeigh;
boolean shouldScaleWidth = hScale > 1;
boolean shouldScaleHeight = vScale > 1;
if (shouldScaleWidth || shouldScaleHeight) {
int w, h;
if (hScale > vScale) {
w = maxWidth;
h = (int) (result.height / hScale);
if (h == 0)
h = 1;
} else {
w = (int) (result.width / vScale);
h = maxHeigh;
if (w == 0)
w = 1;
}
result = result.scaledTo(w, h);
}
}
return result;
}
private IMarker getMarker() {
if (marker == null) {
if (markerRef != null) {
return markerRef.getMarker();
}
}
return marker;
}
private InputStream getStream(int zoom) {
IMarker m = getMarker();
if (m == null)
return null;
IMarkerResource res = m.getResource();
if (res == null)
return null;
IMarkerVariation variation = getMarkerVariation(res);
InputStream in = null;
try {
if (variation == null) {
in = res.openInputStream(zoom);
} else {
in = res.openInputStream(variation, zoom);
if (in == null)
in = res.openInputStream(zoom);
}
} catch (IOException e) {
e.printStackTrace();
}
if (in == null)
return null;
return new BufferedInputStream(in);
}
private IMarkerVariation getMarkerVariation(IMarkerResource res) {
for (IMarkerVariation variation : res.getVariations()) {
if (variation.isApplicable(maxWidth, maxHeigh)) {
return variation;
}
}
return null;
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (obj == null || !(obj instanceof MarkerImageDescriptor))
return false;
MarkerImageDescriptor that = (MarkerImageDescriptor) obj;
if ((this.maxWidth < 0 ? that.maxWidth >= 0
: this.maxWidth != that.maxWidth)
|| (this.maxHeigh < 0 ? that.maxHeigh >= 0
: this.maxHeigh != that.maxHeigh))
return false;
IMarker thisMarker = this.getMarker();
return thisMarker != null && thisMarker.equals(that.getMarker());
}
@Override
public int hashCode() {
return markerId.hashCode();
}
@Override
public String toString() {
return "MarkerImageDescriptor(marker=" + markerId + ")"; //$NON-NLS-1$ //$NON-NLS-2$
}
private static ImageDescriptor getErrorImage() {
if (ErrorImage == null) {
ErrorImage = ImageUtils.createErrorImage(MindMapUI.DEF_MARKER_WIDTH,
MindMapUI.DEF_MARKER_HEIGHT);
}
return ErrorImage;
}
public static ImageDescriptor createFromMarker(IMarker marker) {
if (marker == null)
return getErrorImage();
return new MarkerImageDescriptor(marker, -1, -1);
}
public static ImageDescriptor createFromMarkerRef(IMarkerRef markerRef) {
if (markerRef == null)
return getErrorImage();
return new MarkerImageDescriptor(markerRef, -1, -1);
}
public static ImageDescriptor createFromMarker(IMarker marker, int maxWidth,
int maxHeigh) {
if (marker == null)
return getErrorImage();
return new MarkerImageDescriptor(marker, maxWidth, maxHeigh);
}
public static ImageDescriptor createFromMarker(IMarker marker, int maxWidth,
int maxHeigh, RGB background) {
MarkerImageDescriptor descriptor = (MarkerImageDescriptor) createFromMarker(
marker, maxWidth, maxHeigh);
descriptor.setBackground(background);
return descriptor;
}
public static ImageDescriptor createFromMarker(IMarker marker, int maxWidth,
int maxHeigh, boolean createByStream) {
if (createByStream)
return createFromMarker(marker, maxWidth, maxHeigh);
MarkerImageDescriptor descriptor = (MarkerImageDescriptor) createFromMarker(
marker, maxWidth, maxHeigh);
descriptor.setCreateByStream(createByStream);
return descriptor;
}
public static ImageDescriptor createFromMarkerRef(IMarkerRef markerRef,
int maxWidth, int maxHeigh) {
if (markerRef == null)
return getErrorImage();
return new MarkerImageDescriptor(markerRef, maxWidth, maxHeigh);
}
private void setBackground(RGB background) {
this.background = background;
}
private void setCreateByStream(boolean createByStream) {
this.createByStream = createByStream;
}
}