/* ******************************************************************************
* 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.internal.decorators;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Layer;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Pattern;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.xmind.core.ISheet;
import org.xmind.core.IWorkbook;
import org.xmind.core.util.HyperlinkUtils;
import org.xmind.gef.GEF;
import org.xmind.gef.IGraphicalViewer;
import org.xmind.gef.IViewer;
import org.xmind.gef.graphicalpolicy.IStyleSelector;
import org.xmind.gef.part.Decorator;
import org.xmind.gef.part.IGraphicalPart;
import org.xmind.ui.internal.AttachmentImageDescriptor;
import org.xmind.ui.internal.layers.BackgroundLayer;
import org.xmind.ui.mindmap.IMindMapViewer;
import org.xmind.ui.style.StyleUtils;
import org.xmind.ui.style.Styles;
import org.xmind.ui.util.MindMapUtils;
public class SheetDecorator extends Decorator {
private static final SheetDecorator instance = new SheetDecorator();
private static final String CACHE_WALLPAPER_KEY = "org.xmind.ui.cache.wallpaperKey"; //$NON-NLS-1$
protected static class WallpaperImageRegistry {
private static class Entry {
ImageDescriptor imageDescriptor;
Image image;
Set<IGraphicalPart> hosts;
public Entry(ImageDescriptor key) {
this.imageDescriptor = key;
}
public Image getImage(IGraphicalPart host) {
if (hosts == null)
hosts = new HashSet<IGraphicalPart>();
hosts.add(host);
if (image == null) {
image = imageDescriptor.createImage(false);
}
return image;
}
public void remove(IGraphicalPart host) {
if (hosts != null)
hosts.remove(host);
}
public boolean isEmpty() {
return hosts == null || hosts.isEmpty();
}
public void dispose() {
if (image != null) {
image.dispose();
image = null;
}
}
}
private Map<Object, Entry> map = new HashMap<Object, Entry>();
public Image getImage(IGraphicalPart host, IStyleSelector ss) {
Object oldKey = MindMapUtils.getCache(host, CACHE_WALLPAPER_KEY);
Object newKey = generateKey(host, ss);
MindMapUtils.setCache(host, CACHE_WALLPAPER_KEY, newKey);
if (oldKey != null && !oldKey.equals(newKey)) {
remove(host, oldKey);
}
if (newKey != null) {
Entry entry = map.get(newKey);
if (entry == null) {
if (newKey instanceof ImageDescriptor) {
entry = new Entry((ImageDescriptor) newKey);
} else if (newKey instanceof String) {
ImageDescriptor entryKey = null;
try {
entryKey = ImageDescriptor.createFromURL(new URL(
(String) newKey));
} catch (MalformedURLException e) {
entryKey = ImageDescriptor
.getMissingImageDescriptor();
}
entry = new Entry(entryKey);
}
map.put(newKey, entry);
}
if (entry != null)
return entry.getImage(host);
}
return null;
}
private Object generateKey(IGraphicalPart host, IStyleSelector ss) {
String value = ss.getStyleValue(host, Styles.Background);
if (value != null) {
if (HyperlinkUtils.isAttachmentURL(value)) {
String attachmentPath = HyperlinkUtils
.toAttachmentPath(value);
IWorkbook workbook = getWorkbook(host);
return AttachmentImageDescriptor.createFromEntryPath(
workbook, attachmentPath);
} else if (HyperlinkUtils.isInternalAttachmentURL(value)) {
return value;
}
}
return null;
}
public void removeHost(IGraphicalPart host, IStyleSelector ss) {
Object key = generateKey(host, ss);
if (key != null) {
remove(host, key);
}
}
private void remove(IGraphicalPart host, Object key) {
Entry entry = map.get(key);
if (entry != null) {
entry.remove(host);
if (entry.isEmpty()) {
map.remove(key);
entry.dispose();
}
}
}
private IWorkbook getWorkbook(IGraphicalPart host) {
IViewer viewer = host.getSite().getViewer();
if (viewer instanceof IMindMapViewer) {
ISheet sheet = ((IMindMapViewer) viewer).getSheet();
if (sheet != null)
return sheet.getOwnedWorkbook();
}
return null;
}
public boolean isEmpty() {
return map.isEmpty();
}
}
private WallpaperImageRegistry imageRegistry = null;
private Map<IGraphicalPart, Image> partToWrapImage = new HashMap<IGraphicalPart, Image>();
protected SheetDecorator() {
}
public void decorate(IGraphicalPart part, IFigure figure) {
super.decorate(part, figure);
IStyleSelector ss = StyleUtils.getStyleSelector(part);
decorateSheet(part, ss, figure);
}
private void decorateSheet(IGraphicalPart part, IStyleSelector ss,
IFigure figure) {
IGraphicalViewer viewer = (IGraphicalViewer) part.getSite().getViewer();
Layer layer = viewer.getLayer(GEF.LAYER_BACKGROUND);
if (layer != null) {
decorateBackground(part, ss, layer);
}
}
private void decorateBackground(IGraphicalPart part, IStyleSelector ss,
Layer layer) {
layer.setBackgroundColor(getBackgroundColor(part, ss));
if (layer instanceof BackgroundLayer) {
BackgroundLayer bgLayer = (BackgroundLayer) layer;
Pattern newWallpaper = getWallpaper(part, ss);
Pattern oldWallpaper = bgLayer.getWallpaper();
if (oldWallpaper != null) {
oldWallpaper.dispose();
}
bgLayer.setWallpaper(newWallpaper);
bgLayer.setSubAlpha(getWallpaperAlpha(part, ss));
}
}
private Color getBackgroundColor(IGraphicalPart part, IStyleSelector ss) {
return StyleUtils.getColor(part, ss, Styles.FillColor, null,
Styles.DEF_SHEET_FILL_COLOR);
}
private int getWallpaperAlpha(IGraphicalPart part, IStyleSelector ss) {
double opacity = StyleUtils.getDouble(part, ss, Styles.Opacity, 0.8);
return (int) Math.round(opacity * 255);
}
/**
* Create a new wallpaper pattern or return no pattern.
*
* @param part
* @param ss
* @return
*/
private Pattern getWallpaper(IGraphicalPart part, IStyleSelector ss) {
Image image = getWallpaperImage(part, ss);
Image wrapImage = partToWrapImage.get(part);
if (wrapImage != null) {
wrapImage.dispose();
wrapImage = null;
}
if (image != null) {
Rectangle b = image.getBounds();
wrapImage = new Image(null, b.width, b.height);
GC gc = new GC(wrapImage);
gc.setBackground(getBackgroundColor(part, ss));
gc.fillRectangle(b);
gc.drawImage(image, b.x, b.y);
gc.dispose();
}
partToWrapImage.put(part, wrapImage);
return wrapImage == null ? null : new Pattern(Display.getCurrent(),
wrapImage);
}
private Image getWallpaperImage(IGraphicalPart part, IStyleSelector ss) {
if (imageRegistry == null)
imageRegistry = new WallpaperImageRegistry();
return imageRegistry.getImage(part, ss);
}
public void deactivate(IGraphicalPart part, IFigure figure) {
IGraphicalViewer viewer = (IGraphicalViewer) part.getSite().getViewer();
Layer layer = viewer.getLayer(GEF.LAYER_BACKGROUND);
if (layer instanceof BackgroundLayer) {
Pattern wallpaper = ((BackgroundLayer) layer).getWallpaper();
if (wallpaper != null) {
wallpaper.dispose();
}
((BackgroundLayer) layer).setWallpaper(null);
}
Image wrapImage = partToWrapImage.get(part);
if (wrapImage != null) {
wrapImage.dispose();
wrapImage = null;
}
if (imageRegistry != null) {
imageRegistry.removeHost(part, StyleUtils.getStyleSelector(part));
}
super.deactivate(part, figure);
}
public static SheetDecorator getInstance() {
return instance;
}
}