package com.kreative.paint.document.draw;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.kreative.paint.document.undo.Atom;
import com.kreative.paint.document.undo.History;
import com.kreative.paint.document.undo.Recordable;
public class DrawObjectSurface implements Cloneable, Recordable, DrawSurface {
private int x;
private int y;
private List<DrawObject> objects;
private History history;
private List<DrawObjectSurfaceListener> listeners;
private DrawObjectListener objectListener;
public DrawObjectSurface(int x, int y) {
this.x = x;
this.y = y;
this.objects = new ArrayList<DrawObject>();
this.history = null;
this.listeners = new ArrayList<DrawObjectSurfaceListener>();
this.objectListener = new DrawObjectSurfaceDrawObjectListener(this);
}
private DrawObjectSurface(DrawObjectSurface o) {
this.x = o.x;
this.y = o.y;
this.objects = new ArrayList<DrawObject>();
for (DrawObject d : o.objects) {
this.objects.add(d.clone());
}
this.history = null;
this.listeners = new ArrayList<DrawObjectSurfaceListener>();
this.objectListener = new DrawObjectSurfaceDrawObjectListener(this);
for (DrawObject d : this.objects) {
d.addDrawObjectListener(objectListener);
}
}
@Override
public DrawObjectSurface clone() {
return new DrawObjectSurface(this);
}
@Override
public History getHistory() {
return history;
}
@Override
public void setHistory(History history) {
this.history = history;
for (DrawObject o : objects) o.setHistory(history);
}
public void addDrawObjectSurfaceListener(DrawObjectSurfaceListener l) {
listeners.add(l);
}
public void removeDrawObjectSurfaceListener(DrawObjectSurfaceListener l) {
listeners.remove(l);
}
public DrawObjectSurfaceListener[] getDrawObjectSurfaceListeners() {
return listeners.toArray(new DrawObjectSurfaceListener[listeners.size()]);
}
protected void notifyDrawObjectSurfaceListeners(int id) {
if (listeners.isEmpty()) return;
DrawObjectSurfaceEvent e = new DrawObjectSurfaceEvent(id, this);
switch (id) {
case DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_LOCATION_CHANGED:
for (DrawObjectSurfaceListener l : listeners)
l.drawObjectSurfaceLocationChanged(e);
break;
case DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED:
for (DrawObjectSurfaceListener l : listeners)
l.drawObjectSurfaceContentChanged(e);
break;
}
}
private static class DrawObjectSurfaceDrawObjectListener implements DrawObjectListener {
private final DrawObjectSurface ds;
public DrawObjectSurfaceDrawObjectListener(DrawObjectSurface ds) {
this.ds = ds;
}
@Override
public void drawObjectPaintSettingsChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectTransformChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectVisibleChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectLockedChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectSelectedChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectControlPointChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectLocationChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void drawObjectImplementationPropertyChanged(DrawObjectEvent e) {
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
}
public int getX() { return x; }
public int getY() { return y; }
public Point getLocation() { return new Point(x, y); }
private static class LocationAtom implements Atom {
private DrawObjectSurface ds;
private int oldX, oldY;
private int newX, newY;
public LocationAtom(DrawObjectSurface ds, int newX, int newY) {
this.ds = ds;
this.oldX = ds.x; this.oldY = ds.y;
this.newX = newX; this.newY = newY;
}
@Override
public boolean canBuildUpon(Atom prev) {
return (prev instanceof LocationAtom)
&& (((LocationAtom)prev).ds == this.ds);
}
@Override
public Atom buildUpon(Atom prev) {
this.oldX = ((LocationAtom)prev).oldX;
this.oldY = ((LocationAtom)prev).oldY;
return this;
}
@Override
public void redo() {
ds.x = newX;
ds.y = newY;
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_LOCATION_CHANGED);
}
@Override
public void undo() {
ds.x = oldX;
ds.y = oldY;
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_LOCATION_CHANGED);
}
}
public void setX(int x) {
if (this.x == x) return;
if (history != null) history.add(new LocationAtom(this, x, y));
this.x = x;
this.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_LOCATION_CHANGED);
}
public void setY(int y) {
if (this.y == y) return;
if (history != null) history.add(new LocationAtom(this, x, y));
this.y = y;
this.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_LOCATION_CHANGED);
}
public void setLocation(Point p) {
if (this.x == p.x && this.y == p.y) return;
if (history != null) history.add(new LocationAtom(this, p.x, p.y));
this.x = p.x;
this.y = p.y;
this.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_LOCATION_CHANGED);
}
public void paint(Graphics2D g) {
AffineTransform tx = g.getTransform();
g.translate(x, y);
for (DrawObject o : objects) {
if (o.visible) {
o.paint(g);
}
}
g.setTransform(tx);
}
public void paint(Graphics2D g, int x, int y) {
AffineTransform tx = g.getTransform();
g.translate(this.x + x, this.y + y);
for (DrawObject o : objects) {
if (o.visible) {
o.paint(g);
}
}
g.setTransform(tx);
}
@Override
public boolean hasSelection() {
for (DrawObject o : objects) {
if (o.selected) {
return true;
}
}
return false;
}
@Override
public int getFirstSelectedIndex() {
for (int i = 0; i < objects.size(); i++) {
if (objects.get(i).selected) {
return i;
}
}
return -1;
}
@Override
public int getLastSelectedIndex() {
for (int i = objects.size() - 1; i >= 0; i--) {
if (objects.get(i).selected) {
return i;
}
}
return -1;
}
@Override
public List<DrawObject> getSelection() {
List<DrawObject> selected = new ArrayList<DrawObject>();
for (DrawObject o : objects) {
if (o.selected) {
selected.add(o);
}
}
return selected;
}
@Override
public Graphics2D createDrawGraphics() {
return new DrawObjectSurfaceGraphics(this, this.x, this.y);
}
private static class SetObjectsAtom implements Atom {
private DrawObjectSurface ds;
private List<DrawObject> oldObjects;
private List<DrawObject> newObjects;
public SetObjectsAtom(
DrawObjectSurface ds,
List<DrawObject> oldObjects,
List<DrawObject> newObjects
) {
this.ds = ds;
this.oldObjects = oldObjects;
this.newObjects = newObjects;
}
@Override
public boolean canBuildUpon(Atom prev) {
return (prev instanceof SetObjectsAtom)
&& (((SetObjectsAtom)prev).ds == this.ds);
}
@Override
public Atom buildUpon(Atom prev) {
this.oldObjects = ((SetObjectsAtom)prev).oldObjects;
return this;
}
@Override
public void redo() {
ds.objects.clear();
ds.objects.addAll(newObjects);
for (DrawObject o : oldObjects) {
o.setHistory(null);
o.removeDrawObjectListener(ds.objectListener);
}
for (DrawObject o : newObjects) {
o.setHistory(ds.history);
o.addDrawObjectListener(ds.objectListener);
}
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public void undo() {
ds.objects.clear();
ds.objects.addAll(oldObjects);
for (DrawObject o : newObjects) {
o.setHistory(null);
o.removeDrawObjectListener(ds.objectListener);
}
for (DrawObject o : oldObjects) {
o.setHistory(ds.history);
o.addDrawObjectListener(ds.objectListener);
}
ds.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
}
private List<DrawObject> changing() {
List<DrawObject> oldObjects = new ArrayList<DrawObject>();
oldObjects.addAll(objects);
return oldObjects;
}
private void changed(List<DrawObject> oldObjects) {
List<DrawObject> newObjects = new ArrayList<DrawObject>();
newObjects.addAll(objects);
if (history != null) history.add(new SetObjectsAtom(this, oldObjects, newObjects));
for (DrawObject o : oldObjects) {
o.setHistory(null);
o.removeDrawObjectListener(objectListener);
}
for (DrawObject o : newObjects) {
o.setHistory(history);
o.addDrawObjectListener(objectListener);
}
this.notifyDrawObjectSurfaceListeners(DrawObjectSurfaceEvent.DRAW_OBJECT_SURFACE_CONTENT_CHANGED);
}
@Override
public boolean add(DrawObject o) {
List<DrawObject> c = changing();
boolean r = objects.add(o);
changed(c);
return r;
}
@Override
public void add(int index, DrawObject o) {
List<DrawObject> c = changing();
objects.add(index, o);
changed(c);
}
@Override
public boolean addAll(Collection<? extends DrawObject> coll) {
List<DrawObject> c = changing();
boolean r = objects.addAll(coll);
changed(c);
return r;
}
@Override
public boolean addAll(int index, Collection<? extends DrawObject> coll) {
List<DrawObject> c = changing();
boolean r = objects.addAll(index, coll);
changed(c);
return r;
}
@Override
public void clear() {
List<DrawObject> c = changing();
objects.clear();
changed(c);
}
@Override
public boolean contains(Object o) {
return objects.contains(o);
}
@Override
public boolean containsAll(Collection<?> coll) {
return objects.containsAll(coll);
}
@Override
public DrawObject get(int index) {
return objects.get(index);
}
@Override
public int indexOf(Object o) {
return objects.indexOf(o);
}
@Override
public boolean isEmpty() {
return objects.isEmpty();
}
@Override
public Iterator<DrawObject> iterator() {
return Collections.unmodifiableList(objects).iterator();
}
@Override
public int lastIndexOf(Object o) {
return objects.lastIndexOf(o);
}
@Override
public ListIterator<DrawObject> listIterator() {
return Collections.unmodifiableList(objects).listIterator();
}
@Override
public ListIterator<DrawObject> listIterator(int index) {
return Collections.unmodifiableList(objects).listIterator(index);
}
@Override
public boolean remove(Object o) {
List<DrawObject> c = changing();
boolean r = objects.remove(o);
changed(c);
return r;
}
@Override
public DrawObject remove(int index) {
List<DrawObject> c = changing();
DrawObject r = objects.remove(index);
changed(c);
return r;
}
@Override
public boolean removeAll(Collection<?> coll) {
List<DrawObject> c = changing();
boolean r = objects.removeAll(coll);
changed(c);
return r;
}
@Override
public boolean retainAll(Collection<?> coll) {
List<DrawObject> c = changing();
boolean r = objects.retainAll(coll);
changed(c);
return r;
}
@Override
public DrawObject set(int index, DrawObject o) {
List<DrawObject> c = changing();
DrawObject r = objects.set(index, o);
changed(c);
return r;
}
@Override
public int size() {
return objects.size();
}
@Override
public List<DrawObject> subList(int fromIndex, int toIndex) {
return Collections.unmodifiableList(objects).subList(fromIndex, toIndex);
}
@Override
public Object[] toArray() {
return objects.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return objects.toArray(a);
}
}