+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.image.impl;\r
+\r
+import java.awt.Shape;\r
+import java.awt.geom.Rectangle2D;\r
+import java.lang.ref.WeakReference;\r
+import java.util.EnumSet;\r
+\r
+import org.simantics.g2d.image.Image;\r
+import org.simantics.scenegraph.Node;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.utils.datastructures.ListenerList;\r
+\r
+/**\r
+ * ImageProxy keeps strong reference to an original image, but weak reference\r
+ * from original image to proxy image.\r
+ * <p>\r
+ * Listeners attached to ImageProxy relays events from the original image.\r
+ *\r
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
+ */\r
+public class ImageProxy implements Image {\r
+\r
+ ListenerList<ImageListener> list = null;\r
+\r
+ /** Strong reference to the original image */\r
+ Image source;\r
+ Node node = null;\r
+ /** Listener for the original image */\r
+ WeakImageListener sourceListener;\r
+\r
+ public ImageProxy(Image original) {\r
+ if (original==null) throw new IllegalArgumentException("null arg");\r
+ this.source = original;\r
+ }\r
+\r
+ protected void notifyChanged()\r
+ {\r
+ ImageListener[] listeners;\r
+ synchronized(this) {\r
+ if (list==null) return;\r
+ listeners = list.getListeners();\r
+ }\r
+ for (ImageListener l : listeners)\r
+ l.onContentChangedNotification(this);\r
+ }\r
+\r
+ @Override\r
+ public synchronized void addImageListener(ImageListener listener) {\r
+ if (list==null) list = new ListenerList<ImageListener>(ImageListener.class);\r
+ if (sourceListener==null) {\r
+ sourceListener = new WeakImageListener(this);\r
+ source.addImageListener(sourceListener);\r
+ }\r
+ list.add(listener);\r
+ }\r
+\r
+ @Override\r
+ public synchronized void removeImageListener(ImageListener listener) {\r
+ if (list==null) return;\r
+ list.remove(listener);\r
+ if (list.isEmpty()) {\r
+ source.removeImageListener(sourceListener);\r
+ }\r
+ }\r
+\r
+ static class WeakImageListener implements ImageListener {\r
+ WeakReference<ImageProxy> ref;\r
+ public WeakImageListener(ImageProxy img)\r
+ {\r
+ ref = new WeakReference<ImageProxy>(img);\r
+ }\r
+\r
+ @Override\r
+ public void onContentChangedNotification(Image image) {\r
+ ImageProxy i = ref.get();\r
+ if (i == null) {\r
+ image.removeImageListener(this);\r
+ } else {\r
+ i.notifyChanged();\r
+ }\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Rectangle2D getBounds() {\r
+ return source.getBounds();\r
+ }\r
+\r
+ @Override\r
+ public EnumSet<Feature> getFeatures() {\r
+ return source.getFeatures();\r
+ }\r
+\r
+ @Override\r
+ public Shape getOutline() {\r
+ return source.getOutline();\r
+ }\r
+\r
+ @Override\r
+ public Node init(G2DParentNode parent) {\r
+ this.node = source.init(parent);\r
+ return this.node;\r
+ }\r
+\r
+ public synchronized void setSource(Image newSource) {\r
+ if (newSource==null) throw new IllegalArgumentException("null");\r
+ if (source == newSource) return;\r
+ Image oldSource = source;\r
+ if(node != null) {\r
+ node.remove(); // FIXME\r
+ node = null;\r
+ }\r
+\r
+ source = newSource;\r
+\r
+ if (sourceListener!=null) {\r
+ oldSource.removeImageListener(sourceListener);\r
+ newSource.addImageListener(sourceListener);\r
+ }\r
+\r
+ notifyChanged();\r
+ }\r
+\r
+}\r
+\r