package ie.dcu.swt; import ie.dcu.swt.event.*; import java.util.*; import org.eclipse.swt.graphics.*; public class ObservableImage { private final List listeners; private Image image; private ImageData data; private Rectangle modified; private GC gc; private int refCount; private boolean suspendNotifications; public ObservableImage(Image image) { this.listeners = new ArrayList(2); this.image = image; } public GC beginPaint() { if (refCount > 0) { refCount++; return gc; } else { modified = null; refCount = 1; return (gc = new GC(image)); } } public void endPaint() { endPaint(null); } public void endPaint(Rectangle modified) { refCount--; if (refCount < 0) { throw new IllegalStateException(); } updateModified(modified); if (refCount == 0) { data = null; gc.dispose(); gc = null; fireImageChanged(); } } public Image getImage() { return image; } public ImageData getImageData() { if (data == null) { data = image.getImageData(); } return data; } public void setImage(Image image, boolean disposeOld) { if (gc != null) { throw new IllegalStateException(); } if (image == null) { throw new NullPointerException(); } boolean dimensionsChanged = false; if (this.image != null && !this.image.isDisposed()) { Rectangle oldBounds = this.image.getBounds(); Rectangle newBounds = image.getBounds(); dimensionsChanged = !oldBounds.equals(newBounds); } else { dimensionsChanged = true; } if (disposeOld) { dispose(); } this.image = image; // Invalidate cached image data this.data = null; fireImageChanged(dimensionsChanged); } public void setSuspendNotifications(boolean suspend) { this.suspendNotifications = suspend; } public boolean isDisposed() { if (image != null) { return image.isDisposed(); } return false; } public void dispose() { if (image != null && !image.isDisposed()) { image.dispose(); } data = null; } public Rectangle getBounds() { return image.getBounds(); } public Rectangle getModifiedArea() { return modified; } public void addImageListener(ImageListener listener) { listeners.add(listener); } public void removeImageListener(ImageListener listener) { listeners.remove(listener); } public void fireImageChanged() { fireImageChanged(getModifiedArea(), false); } public void fireImageChanged(Rectangle modified) { fireImageChanged(modified, false); } private void fireImageChanged(boolean dimensionsChanged) { fireImageChanged(getModifiedArea(), dimensionsChanged); } private void fireImageChanged(Rectangle modified, boolean dimensionsChanged) { if (suspendNotifications) { return; } ImageEvent e = null; for (ImageListener i : listeners) { if (e == null) { e = new ImageEvent(this, modified, dimensionsChanged); } i.imageChanged(e); } } private void updateModified(Rectangle m) { if (m == null) { this.modified = image.getBounds(); } else { if (this.modified != null) { this.modified = this.modified.union(m); } else { this.modified = SwtUtils.clone(m); } } } }